diff --git a/.github/print-logs.php b/.github/print-logs.php index 550f0d2f49..a3cf1ae01e 100644 --- a/.github/print-logs.php +++ b/.github/print-logs.php @@ -16,7 +16,7 @@ } echo '[Swoole Component]', \PHP_EOL; -$fileName = \dirname(__DIR__) . '/tests/unit/Component/logs/log-' . date('Y-m-d') . '.log'; +$fileName = \dirname(__DIR__) . 'src/Components/swoole/tests/unit/Component/logs/log-' . date('Y-m-d') . '.log'; if (is_file($fileName)) { echo file_get_contents($fileName), \PHP_EOL; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d108cee398..693530b9ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -281,12 +281,14 @@ jobs: strategy: fail-fast: false matrix: - php: [7.4, "8.0", "8.1"] - swoole: [v5.0.3, v4.8.11] + php: ["7.4", "8.0", "8.1", "8.2"] + swoole: [v5.0.3, v4.8.13] roadrunner: [2.7.*] exclude: - php: 7.4 swoole: v5.0.3 + - php: 8.2 + swoole: v4.8.13 env: MYSQL_SERVER_PASSWORD: "root" PHP_VERSION: ${{ matrix.php }} @@ -405,9 +407,12 @@ jobs: strategy: fail-fast: false matrix: - php: [7.4, "8.0", 8.1] + php: ["7.4", "8.0", "8.1"] # 部分扩展还未在 pecl 发布 PHP 8.2 Windows 版扩展,所以无法测试 roadrunner: [2.7.*] - + extensions: + [ + "apcu, bcmath, curl, openssl, mbstring, intl, json, redis, mysqli, pdo, pdo_mysql, sockets", + ] env: IMI_ROADRUNNER_BINARY: ${{ github.workspace }}\rr.exe GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -435,7 +440,7 @@ jobs: php-version: ${{ matrix.php }} ini-values: session.save_path=C:\temp tools: pecl - extensions: apcu, bcmath, curl, openssl, mbstring, intl, json, redis, mysqli, pdo, pdo_mysql, sockets + extensions: ${{ matrix.extensions }} env: fail-fast: true @@ -489,7 +494,7 @@ jobs: # swoole: # # - version: v5.0.3 # # postgresql_version: "" - # # - version: v4.8.11 + # # - version: v4.8.13 # # postgresql_version: "" # - version: fix-curl-hook-php8.2 # postgresql_version: "" diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index f8c374f45d..d58ae8241a 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -13,8 +13,11 @@ on: pull_request: jobs: - tests: + test: runs-on: ubuntu-latest + strategy: + matrix: + testType: [core, swoole, components] services: zookeeper: image: zookeeper:3.4 @@ -97,6 +100,7 @@ jobs: --health-timeout=5s --health-retries=3 env: + TEST_TYPE: ${{ matrix.testType }} SWOOLE_VERSION: v5.0.3 ROADRUNNER_VERSION: 2.7.* IMI_ROADRUNNER_BINARY: ${{ github.workspace }}/rr @@ -110,6 +114,7 @@ jobs: --enable-swoole-json --enable-swoole-curl --enable-swoole-pgsql + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout uses: actions/checkout@v2 @@ -118,18 +123,27 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.1 + php-version: 8.2 tools: pecl coverage: xdebug extensions: > apcu, bcmath, curl, openssl, mbstring, intl, json, redis, mysqli, pdo, pdo_mysql, pdo_pgsql, - sockets, zip, inotify, event, apcu, + sockets, zip, inotify, event swoole-swoole/swoole-src@${{ env.SWOOLE_VERSION }} - name: Check Version run: | php -v php -m php --ri swoole + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + - name: Cache vendor + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- - name: Prepare run: | printf "127.0.0.1\tkafka1\n" | sudo tee -a /etc/hosts @@ -139,160 +153,67 @@ jobs: PGPASSWORD=root psql -h 127.0.0.1 -d db_imi_test -U root -f ./.github/pgsql.sql src/Components/roadrunner/vendor/bin/rr get-binary -f $ROADRUNNER_VERSION ./rr -v - echo "test_ready=1" >> $GITHUB_ENV - - name: Run core test suite - timeout-minutes: 5 - run: php vendor/bin/phpunit -c ./tests/phpunit.xml --coverage-clover=./core-coverage.xml -v - - name: Run swoole test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 5 - run: > - php src/Components/swoole/bin/swoole-phpunit - -c ./src/Components/swoole/tests/phpunit.xml - --coverage-clover=./swoole-coverage.xml -v - - name: Run workerman test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/workerman/vendor/bin/phpunit - -c ./src/Components/workerman/tests/phpunit.xml - --coverage-clover=./workerman-coverage.xml -v - - name: Run workerman-gateway test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/workerman-gateway/vendor/bin/phpunit - -c ./src/Components/workerman-gateway/tests/phpunit.xml - --testsuite workerman - --coverage-clover=./workerman-gateway-coverage.xml -v - - name: Run workerman-gateway(swoole) test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/workerman-gateway/vendor/bin/phpunit - -c ./src/Components/workerman-gateway/tests/phpunit.xml - --testsuite swoole - --coverage-clover=./workerman-gateway-swoole-coverage.xml -v - - name: Run roadrunner test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/roadrunner/vendor/bin/phpunit - -c ./src/Components/roadrunner/tests/phpunit.xml - --coverage-clover=./roadrunner-coverage.xml -v - - name: Run fpm test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/fpm/vendor/bin/phpunit - -c ./src/Components/fpm/tests/phpunit.xml - --coverage-clover=./fpm-coverage.xml -v - - name: Run jwt test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/jwt/vendor/bin/phpunit - -c ./src/Components/jwt/tests/phpunit.xml - --coverage-clover=./jwt-coverage.xml -v - - name: Run queue test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/swoole/bin/swoole-phpunit - -c ./src/Components/queue/tests/phpunit.xml - --coverage-clover=./queue-coverage.xml -v - - name: Run amqp-swoole test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - AMQP_TEST_MODE=swoole php src/Components/swoole/bin/swoole-phpunit - -c ./src/Components/amqp/tests/phpunit.xml - --coverage-clover=./amqp-swoole-coverage.xml -v - - name: Run amqp-workerman test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - AMQP_TEST_MODE=workerman php src/Components/swoole/bin/swoole-phpunit - -c ./src/Components/amqp/tests/phpunit.xml - --coverage-clover=./amqp-workerman-coverage.xml -v - - name: Run kafka-swoole test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - KAFKA_TEST_MODE=swoole php src/Components/swoole/bin/swoole-phpunit - -c ./src/Components/kafka/tests/phpunit.xml - --coverage-clover=./kafka-swoole-coverage.xml -v - - name: Run kafka-workerman test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - KAFKA_TEST_MODE=workerman php src/Components/swoole/bin/swoole-phpunit - -c ./src/Components/kafka/tests/phpunit.xml - --coverage-clover=./kafka-workerman-coverage.xml -v - - name: Run grpc test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/swoole/bin/swoole-phpunit - -c ./src/Components/grpc/tests/phpunit.xml - --coverage-clover=./grpc-coverage.xml -v - - name: Run snowflake test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/snowflake/vendor/bin/phpunit - -c ./src/Components/snowflake/tests/phpunit.xml - --coverage-clover=./snowflake-coverage.xml -v - - name: Run mqtt test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/swoole/bin/swoole-phpunit - -c ./src/Components/mqtt/tests/phpunit.xml - --coverage-clover=./mqtt-coverage.xml -v - - name: Run smarty test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/swoole/bin/swoole-phpunit - -c ./src/Components/smarty/tests/phpunit.xml - --coverage-clover=./smarty-coverage.xml -v - - name: Run pgsql test suite - if: ${{ env.test_ready && always() }} - timeout-minutes: 3 - run: > - php src/Components/swoole/bin/swoole-phpunit - -c ./src/Components/pgsql/tests/phpunit.xml - --coverage-clover=./pgsql-coverage.xml -v - - name: Print logs - if: failure() - run: php .github/print-logs.php + - name: Run test suite + id: run-test-suite + run: ./dev/test-coverage-actions.sh php $TEST_TYPE + - name: Upload coverage file + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.testType }}-coverage + path: tests/coverage.php + - name: Upload log files + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.testType }}-logs + path: | + tests/unit/Component/logs/*.log + src/Components/*/tests/*/*/logs/*.log + src/Components/*/example/.runtime/logs/*.log + upload-coverage: + runs-on: ubuntu-latest + needs: test + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + tools: pecl + extensions: > + bcmath, curl, openssl, mbstring, intl, json, sockets, zip, event + - name: Check Version + run: | + php -v + php -m + - name: Prepare + run: | + composer update --prefer-dist --no-progress + mkdir -p ./dev/cover + - name: Download core coverage + uses: actions/download-artifact@v3 + with: + name: core-coverage + path: ./dev/cover/core-coverage.php + - name: Download swoole coverage + uses: actions/download-artifact@v3 + with: + name: swoole-coverage + path: ./dev/cover/swoole-coverage.php + - name: Download components coverage + uses: actions/download-artifact@v3 + with: + name: components-coverage + path: ./dev/cover/components-coverage.php + - name: Parse coverage data + run: php ./dev/merge-coverage.php clover - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} - file: "./core-coverage.xml,\ - ./swoole-coverage.xml,\ - ./workerman-coverage.xml,\ - ./workerman-gateway-coverage.xml,\ - ./workerman-gateway-swoole-coverage.xml,\ - ./roadrunner-coverage.xml,\ - ./fpm-coverage.xml,\ - ./jwt-coverage.xml,\ - ./queue-coverage.xml,\ - ./amqp-swoole-coverage.xml,\ - ./amqp-workerman-coverage.xml,\ - ./kafka-swoole-coverage.xml,\ - ./kafka-workerman-coverage.xml,\ - ./grpc-coverage.xml,\ - ./amqp-swoole-coverage.xml,\ - ./amqp-workerman-coverage.xml,\ - ./kafka-swoole-coverage.xml,\ - ./kafka-workerman-coverage.xml,\ - ./grpc-coverage.xml,\ - ./snowflake-coverage.xml,\ - ./mqtt-coverage.xml,\ - ./smarty-coverage.xml,\ - ./pgsql-coverage.xml" - flags: unittests - name: umbrella \ No newline at end of file + file: "./tests/coverage.xml" + - name: Upload coverage reports to artifact + uses: actions/upload-artifact@v3 + with: + name: coverage + path: tests/coverage.xml diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml index a45dcacd38..b24035e1f4 100644 --- a/.github/workflows/mirror.yml +++ b/.github/workflows/mirror.yml @@ -10,6 +10,7 @@ on: jobs: gitee: if: github.repository == 'imiphp/imi' && (github.ref == 'refs/heads/2.1') + concurrency: ci-${{ github.ref }} runs-on: ubuntu-20.04 steps: - name: Configure Private Key diff --git a/.github/workflows/split-repository.yml b/.github/workflows/split-repository.yml index b913635ae8..81e1fd5d16 100644 --- a/.github/workflows/split-repository.yml +++ b/.github/workflows/split-repository.yml @@ -3,13 +3,14 @@ name: split repository on: push: branches: - - '2.1' + - "2.1" release: types: [published] jobs: split-repository: if: github.repository == 'imiphp/imi' + concurrency: ci-${{ github.ref }} runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index 3101530164..bf8016811a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ composer.lock *.macro.php /.phpbench /node_modules +/tests/clover.xml +/tests/html-coverage +/dev/cover diff --git a/README.md b/README.md index 943841dfc1..9860cc692d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ [![imi Doc](https://img.shields.io/badge/docs-passing-green.svg)](https://doc.imiphp.com/v2.1/) [![imi License](https://img.shields.io/badge/license-MulanPSL%202.0-brightgreen.svg)](https://github.com/imiphp/imi/blob/master/LICENSE) [![star](https://gitee.com/yurunsoft/IMI/badge/star.svg?theme=gvp)](https://gitee.com/yurunsoft/IMI/stargazers) -[![codecov](https://codecov.io/github/imiphp/imi/branch/dev/graph/badge.svg?token=YrNRQgbRe2)](https://codecov.io/github/imiphp/imi) +[![codecov](https://codecov.io/github/imiphp/imi/branch/2.1/graph/badge.svg?token=YrNRQgbRe2)](https://codecov.io/github/imiphp/imi) ## 介绍 diff --git a/composer.json b/composer.json index 663d332a8f..8760f26aea 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,11 @@ "autoload-dev": { "psr-4": { "Imi\\Dev\\": "dev/", - "Imi\\Test\\": "tests/unit/" + "Imi\\Test\\": "tests/unit/", + "Imi\\Test\\Unused\\": [ + "tests/unit/unused1", + "tests/unit/unused2" + ] }, "files": [ "dev/bootstrap.php", @@ -82,6 +86,10 @@ "install-components": "Imi\\Dev\\Plugin::dev", "generate-ide-helper": "Imi\\Dev\\Plugin::IDEHelper", "test": "@php -dapc.enable_cli=1 vendor/bin/phpunit -c ./tests/phpunit.xml", + "test-coverage": [ + "Composer\\Config::disableProcessTimeout", + "./dev/test-coverage.sh" + ], "install-test": "@php --ri swoole && composer install && cd ../ && composer test", "test-swoole": "@php src/Components/swoole/bin/swoole-phpunit -c src/Components/swoole/tests/phpunit.xml", "test-workerman": "@php src/Components/workerman/vendor/bin/phpunit -c src/Components/workerman/tests/phpunit.xml", @@ -136,4 +144,4 @@ ] } } -} +} \ No newline at end of file diff --git a/dev/bootstrap.php b/dev/bootstrap.php index 1dc9c624bc..4eeebfa247 100644 --- a/dev/bootstrap.php +++ b/dev/bootstrap.php @@ -2,8 +2,13 @@ declare(strict_types=1); +use Imi\Event\Event; use Rector\Config\RectorConfig; use Rector\Set\ValueObject\LevelSetList; +use SebastianBergmann\CodeCoverage\CodeCoverage; +use SebastianBergmann\CodeCoverage\Driver\Selector; +use SebastianBergmann\CodeCoverage\Filter; +use SebastianBergmann\CodeCoverage\Report\PHP; ini_set('date.timezone', 'Asia/Shanghai'); @@ -37,3 +42,135 @@ function getRectorConfigCallback(string $path): callable $rectorConfig->sets([LevelSetList::UP_TO_PHP_74]); }; } + +function isCodeCoverage(): bool +{ + return (bool) (getenv('IMI_CODE_COVERAGE') ?: false); +} + +function getCodeCoverageName(): string +{ + static $name; + if (null === $name) + { + $name = getenv('IMI_CODE_COVERAGE_NAME'); + if (false === $name) + { + $name = (string) getmypid(); + } + } + + return $name; +} + +function getTestPhpBinary(): string +{ + $result = '"' . \PHP_BINARY . '"'; + if (!isCodeCoverage()) + { + return $result; + } + + return $result . (\extension_loaded('xdebug') ? '' : ' -dzend_extension=xdebug') . ' -dxdebug.mode=coverage'; +} + +/** + * @return string[] + */ +function getTestPhpBinaryArray(): array +{ + $result = [ + \PHP_BINARY, + ]; + if (isCodeCoverage()) + { + if (!\extension_loaded('xdebug')) + { + $result[] = '-dzend_extension=xdebug'; + } + $result[] = '-dxdebug.mode=coverage'; + } + + return $result; +} + +/** + * 检查端口是否可以被绑定. + */ +function checkPort(string $host, int $port, ?int &$errno = null, ?string &$errstr = null): bool +{ + try + { + $socket = @stream_socket_client('tcp://' . $host . ':' . $port, $errno, $errstr, 3); + if (!$socket) + { + return false; + } + fclose($socket); + + return true; + } + catch (\Throwable $th) + { + return false; + } +} + +/** + * 批量检查端口是否可以被绑定. + */ +function checkPorts(array $ports, string $host = '127.0.0.1', int $tryCount = 30, int $sleep = 1): void +{ + echo 'checking ports...', \PHP_EOL; + foreach ($ports as $port) + { + echo "checking port {$port}..."; + $count = 0; + while (checkPort($host, $port)) + { + if ($count >= $tryCount) + { + echo 'failed', \PHP_EOL; + continue 2; + } + ++$count; + sleep($sleep); + } + echo 'OK', \PHP_EOL; + } +} + +if (isCodeCoverage()) +{ + putenv('IMI_CODE_COVERAGE_NAME=' . getCodeCoverageName()); + (static function () { + $filter = new Filter(); + $filter->includeDirectory(\dirname(__DIR__) . '/src'); + $componentsDir = \dirname(__DIR__) . '/src/Components'; + $filter->excludeDirectory($componentsDir); + foreach (new \FilesystemIterator($componentsDir, \FilesystemIterator::SKIP_DOTS) as $dir) + { + if (!$dir->isDir()) + { + continue; + } + $filter->includeDirectory($dir->getPathname() . '/src'); + } + + $codeCoverage = new CodeCoverage((new Selector())->forLineCoverage($filter), $filter); + $codeCoverage->start('imi'); + + $stoped = false; + $shutdownCallback = static function () use ($codeCoverage, &$stoped) { + if (!$stoped) + { + $stoped = true; + $codeCoverage->stop(); + (new PHP())->process($codeCoverage, __DIR__ . '/cover/' . getenv('IMI_CODE_COVERAGE_NAME') . '/' . getmypid() . random_int(0, \PHP_INT_MAX) . '.clover.php'); + } + }; + + Event::on('IMI.SERVER.WORKER_STOP', $shutdownCallback); + register_shutdown_function($shutdownCallback); + })(); +} diff --git a/dev/merge-coverage.php b/dev/merge-coverage.php new file mode 100644 index 0000000000..3050a0f5bc --- /dev/null +++ b/dev/merge-coverage.php @@ -0,0 +1,50 @@ +merge($tmpCodeCoverage); + } + else + { + $codeCoverage = $tmpCodeCoverage; + } + } +} + +if (!isset($codeCoverage)) +{ + throw new \RuntimeException('No coverage data'); +} + +echo 'Generating coverage report...', \PHP_EOL; + +switch ($_SERVER['argv'][1] ?? 'html') +{ + case 'clover': + (new Clover())->process($codeCoverage, ROOT_DIR . '/tests/coverage.xml'); + break; + case 'php': + (new \SebastianBergmann\CodeCoverage\Report\PHP())->process($codeCoverage, ROOT_DIR . '/tests/coverage.php'); + break; + default: + // html + (new Facade())->process($codeCoverage, ROOT_DIR . '/tests/html-coverage'); + break; +} diff --git a/dev/test-coverage-actions.sh b/dev/test-coverage-actions.sh new file mode 100755 index 0000000000..49b83121cc --- /dev/null +++ b/dev/test-coverage-actions.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +test() { + local name=$1 + local cmd=$2 + echo "test $name..."; + time $cmd +} + +__DIR__=$(cd `dirname $0`; pwd) && \ + +cd $__DIR__/../ && \ + +rm -rf dev/cover/* + +export IMI_CODE_COVERAGE=1 + +php --ri xdebug > /dev/null +if [ $? = 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? = 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +testType=$2 + +phpUnitCommands=() +swoolePhpUnitCommands=() + +if [[ $testType = "core" ]]; then + # core test + test "core" "php $paramsXdebug -dxdebug.mode=coverage -dapc.enable_cli=1 vendor/bin/phpunit -c ./tests/phpunit.xml --coverage-php=./dev/cover/core-coverage.php -v" +elif [[ $testType = "swoole" ]]; then + swoolePhpUnitCommands=( + "swoole" + ) +elif [[ $testType = "components" ]]; then + swoolePhpUnitCommands=( + "queue" + "grpc" + "mqtt" + "smarty" + "pgsql" + ) + phpUnitCommands=( + "workerman" + "roadrunner" + "fpm" + "jwt" + "snowflake" + ) + + test "workerman-gateway-workerman" "php $paramsXdebug -dxdebug.mode=coverage src/Components/workerman-gateway/vendor/bin/phpunit -c ./src/Components/workerman-gateway/tests/phpunit.xml --testsuite workerman --coverage-php=./dev/cover/workerman-gateway-coverage.php -v" + + test "workerman-gateway-swoole" "php $paramsXdebug -dxdebug.mode=coverage src/Components/workerman-gateway/vendor/bin/phpunit -c ./src/Components/workerman-gateway/tests/phpunit.xml --testsuite swoole --coverage-php=./dev/cover/workerman-gateway-swoole-coverage.php -v" + + export AMQP_TEST_MODE=swoole + test "amqp-swoole" "php $paramsXdebug -dxdebug.mode=coverage src/Components/swoole/bin/swoole-phpunit -c ./src/Components/amqp/tests/phpunit.xml --coverage-php=./dev/cover/amqp-swoole-coverage.php -v" + + export AMQP_TEST_MODE=workerman + test "amqp-workerman" "php $paramsXdebug -dxdebug.mode=coverage src/Components/swoole/bin/swoole-phpunit -c ./src/Components/amqp/tests/phpunit.xml --coverage-php=./dev/cover/amqp-workerman-coverage.php -v" + + export KAFKA_TEST_MODE=swoole + test "kafka-swoole" "php $paramsXdebug -dxdebug.mode=coverage src/Components/swoole/bin/swoole-phpunit -c ./src/Components/kafka/tests/phpunit.xml --coverage-php=./dev/cover/kafka-swoole-coverage.php -v" + + export KAFKA_TEST_MODE=workerman + test "kafka-workerman" "php $paramsXdebug -dxdebug.mode=coverage src/Components/swoole/bin/swoole-phpunit -c ./src/Components/kafka/tests/phpunit.xml --coverage-php=./dev/cover/kafka-workerman-coverage.php -v" +else + echo "未知的测试类型:$testType" + exit 1 +fi + +for name in "${phpUnitCommands[@]}" +do + cmd="php $paramsXdebug -dxdebug.mode=coverage src/Components/$name/vendor/bin/phpunit -c ./src/Components/$name/tests/phpunit.xml --coverage-php=./dev/cover/$name-coverage.php -v" + test "$name" "$cmd" +done + +for name in "${swoolePhpUnitCommands[@]}" +do + cmd="php $paramsXdebug -dxdebug.mode=coverage src/Components/swoole/bin/swoole-phpunit -c ./src/Components/$name/tests/phpunit.xml --coverage-php=./dev/cover/$name-coverage.php -v" + test "$name" "$cmd" +done + +php dev/merge-coverage.php $1 diff --git a/dev/test-coverage.sh b/dev/test-coverage.sh new file mode 100755 index 0000000000..458d630bec --- /dev/null +++ b/dev/test-coverage.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +test() { + local name=$1 + local cmd=$2 + echo "test $name..."; + time $cmd +} + +__DIR__=$(cd `dirname $0`; pwd) && \ + +cd $__DIR__/../ && \ + +rm -rf dev/cover/* + +export IMI_CODE_COVERAGE=1 + +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +# core test +test "core" "php $paramsXdebug -dxdebug.mode=coverage -dapc.enable_cli=1 vendor/bin/phpunit -c ./tests/phpunit.xml --coverage-php=./dev/cover/core-coverage.php -v" + +phpUnitCommands=( + "workerman" + "roadrunner" + "fpm" + "jwt" + "snowflake" +) + +swoolePhpUnitCommands=( + "swoole" + "queue" + "grpc" + "mqtt" + "smarty" + "pgsql" +) + +for name in "${phpUnitCommands[@]}" +do + cmd="php $paramsXdebug -dxdebug.mode=coverage src/Components/$name/vendor/bin/phpunit -c ./src/Components/$name/tests/phpunit.xml --coverage-php=./dev/cover/$name-coverage.php -v" + test "$name" "$cmd" +done + +for name in "${swoolePhpUnitCommands[@]}" +do + cmd="php $paramsXdebug -dxdebug.mode=coverage src/Components/swoole/bin/swoole-phpunit -c ./src/Components/$name/tests/phpunit.xml --coverage-php=./dev/cover/$name-coverage.php -v" + test "$name" "$cmd" +done + +export AMQP_TEST_MODE=swoole +test "amqp-swoole" "php $paramsXdebug -dxdebug.mode=coverage src/Components/swoole/bin/swoole-phpunit -c ./src/Components/amqp/tests/phpunit.xml --coverage-php=./dev/cover/amqp-swoole-coverage.php -v" + +export AMQP_TEST_MODE=workerman +test "amqp-workerman" "php $paramsXdebug -dxdebug.mode=coverage src/Components/swoole/bin/swoole-phpunit -c ./src/Components/amqp/tests/phpunit.xml --coverage-php=./dev/cover/amqp-workerman-coverage.php -v" + +export KAFKA_TEST_MODE=swoole +test "kafka-swoole" "php $paramsXdebug -dxdebug.mode=coverage src/Components/swoole/bin/swoole-phpunit -c ./src/Components/kafka/tests/phpunit.xml --coverage-php=./dev/cover/kafka-swoole-coverage.php -v" + +export KAFKA_TEST_MODE=workerman +test "kafka-workerman" "php $paramsXdebug -dxdebug.mode=coverage src/Components/swoole/bin/swoole-phpunit -c ./src/Components/kafka/tests/phpunit.xml --coverage-php=./dev/cover/kafka-workerman-coverage.php -v" + +test "workerman-gateway-workerman" "php $paramsXdebug -dxdebug.mode=coverage src/Components/workerman-gateway/vendor/bin/phpunit -c ./src/Components/workerman-gateway/tests/phpunit.xml --testsuite workerman --coverage-php=./dev/cover/workerman-gateway-coverage.php -v" + +test "workerman-gateway-swoole" "php $paramsXdebug -dxdebug.mode=coverage src/Components/workerman-gateway/vendor/bin/phpunit -c ./src/Components/workerman-gateway/tests/phpunit.xml --testsuite swoole --coverage-php=./dev/cover/workerman-gateway-swoole-coverage.php -v" + +php dev/merge-coverage.php $1 diff --git a/doc/base/config.md b/doc/base/config.md index bd5690efcf..575cee5d6b 100644 --- a/doc/base/config.md +++ b/doc/base/config.md @@ -215,6 +215,12 @@ return [ ], ], ], + 'workerman' => [ + // 设置给 Worker 类静态属性的配置 + 'worker' => [ + + ], + ], ]; ``` diff --git a/doc/components/db/index.md b/doc/components/db/index.md index afc99d4d01..c98c0d2de7 100644 --- a/doc/components/db/index.md +++ b/doc/components/db/index.md @@ -297,7 +297,7 @@ public function create() **部分回滚:** -`@Transaction(rollbackType=RollbackType::PART, rollbackLevels="回滚层数,默认为1")` +`@Transaction(rollbackType=RollbackType::PART, rollbackLevels="回滚层数,默认为1;当 $rollbackType 为 RollbackType::PART 时有效。设为null则全部回滚")` **事务监听:** diff --git a/src/Aop/AopAnnotationLoader.php b/src/Aop/AopAnnotationLoader.php index 158010c84e..bb8c673df0 100644 --- a/src/Aop/AopAnnotationLoader.php +++ b/src/Aop/AopAnnotationLoader.php @@ -17,11 +17,9 @@ class AopAnnotationLoader { - private static bool $loaded = false; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static bool $loaded = false; public static function load(bool $force = true): void { diff --git a/src/Aop/AopManager.php b/src/Aop/AopManager.php index 2c9d2b75c0..164390c54d 100644 --- a/src/Aop/AopManager.php +++ b/src/Aop/AopManager.php @@ -12,6 +12,8 @@ */ class AopManager { + use \Imi\Util\Traits\TStaticClass; + /** * @var AopItem[][][] */ @@ -29,10 +31,6 @@ class AopManager */ private static array $dynamicRulesCache = []; - private function __construct() - { - } - public static function getCache(): array { return self::$cache; diff --git a/src/Aop/PointCutType.php b/src/Aop/PointCutType.php index 9d5347af96..82c7bd202c 100644 --- a/src/Aop/PointCutType.php +++ b/src/Aop/PointCutType.php @@ -9,6 +9,8 @@ */ class PointCutType { + use \Imi\Util\Traits\TStaticClass; + /** * 方法. */ @@ -28,8 +30,4 @@ class PointCutType * 带有注解的类的构造方法. */ public const ANNOTATION_CONSTRUCT = 4; - - private function __construct() - { - } } diff --git a/src/App.php b/src/App.php index cedd72db4e..361306a164 100644 --- a/src/App.php +++ b/src/App.php @@ -16,6 +16,8 @@ class App { + use \Imi\Util\Traits\TStaticClass; + /** * 应用命名空间. */ @@ -61,10 +63,6 @@ class App */ private static IApp $app; - private function __construct() - { - } - /** * 框架服务运行入口. * diff --git a/src/AppContexts.php b/src/AppContexts.php index a4921067cd..4d569b651d 100644 --- a/src/AppContexts.php +++ b/src/AppContexts.php @@ -6,6 +6,8 @@ class AppContexts { + use \Imi\Util\Traits\TStaticClass; + /** * 应用命名空间根所在路径. */ @@ -15,8 +17,4 @@ class AppContexts * 应用命名空间根所在物理路径. */ public const APP_PATH_PHYSICS = 'app_path_physics'; - - private function __construct() - { - } } diff --git a/src/Async/Async.php b/src/Async/Async.php index 13c7d147cf..438c220497 100644 --- a/src/Async/Async.php +++ b/src/Async/Async.php @@ -11,11 +11,9 @@ class Async { - private static IAsyncHandler $handler; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static IAsyncHandler $handler; /** * 获取实例. diff --git a/src/Bean/Annotation/AnnotationManager.php b/src/Bean/Annotation/AnnotationManager.php index 05b59b6717..54a23f1756 100644 --- a/src/Bean/Annotation/AnnotationManager.php +++ b/src/Bean/Annotation/AnnotationManager.php @@ -14,6 +14,8 @@ class AnnotationManager { + use \Imi\Util\Traits\TStaticClass; + /** * 注解列表. * @@ -30,10 +32,6 @@ class AnnotationManager private static bool $removeWhenset = true; - private function __construct() - { - } - public static function init(): void { self::$annotationRelation = new AnnotationRelation(); diff --git a/src/Bean/BeanFactory.php b/src/Bean/BeanFactory.php index 8fe7b7ccf7..fb8bb94d01 100644 --- a/src/Bean/BeanFactory.php +++ b/src/Bean/BeanFactory.php @@ -9,6 +9,8 @@ class BeanFactory { + use \Imi\Util\Traits\TStaticClass; + /** * 计数器. */ @@ -24,10 +26,6 @@ class BeanFactory */ public static bool $enableFileCache = false; - private function __construct() - { - } - /** * 实例化. * diff --git a/src/Bean/BeanManager.php b/src/Bean/BeanManager.php index f1c5079947..0c1e7b9a88 100644 --- a/src/Bean/BeanManager.php +++ b/src/Bean/BeanManager.php @@ -11,11 +11,9 @@ */ class BeanManager { - private static array $map = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $map = []; public static function getMap(): array { diff --git a/src/Bean/PartialManager.php b/src/Bean/PartialManager.php index 9c5bdfd54e..2a71ae0b3c 100644 --- a/src/Bean/PartialManager.php +++ b/src/Bean/PartialManager.php @@ -9,11 +9,9 @@ */ class PartialManager { - private static array $map = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $map = []; public static function getMap(): array { diff --git a/src/Bean/ReflectionContainer.php b/src/Bean/ReflectionContainer.php index 979eacffab..f225cc3377 100644 --- a/src/Bean/ReflectionContainer.php +++ b/src/Bean/ReflectionContainer.php @@ -9,6 +9,8 @@ */ class ReflectionContainer { + use \Imi\Util\Traits\TStaticClass; + /** * 类反射集合. */ @@ -24,10 +26,6 @@ class ReflectionContainer */ private static array $propertyReflectionMap = []; - private function __construct() - { - } - /** * 获取类反射. */ diff --git a/src/Bean/ReflectionUtil.php b/src/Bean/ReflectionUtil.php index 278124b58d..01c16c7bf7 100644 --- a/src/Bean/ReflectionUtil.php +++ b/src/Bean/ReflectionUtil.php @@ -6,9 +6,7 @@ class ReflectionUtil { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; public static function getTypeComments(?\ReflectionType $type, ?string $className = null): string { diff --git a/src/Bean/Scanner.php b/src/Bean/Scanner.php index 828698b4e5..d3d112f932 100644 --- a/src/Bean/Scanner.php +++ b/src/Bean/Scanner.php @@ -22,9 +22,7 @@ */ class Scanner { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 扫描 imi 框架. diff --git a/src/Cache/CacheManager.php b/src/Cache/CacheManager.php index acf5f8a673..363feb8355 100644 --- a/src/Cache/CacheManager.php +++ b/src/Cache/CacheManager.php @@ -10,6 +10,8 @@ class CacheManager { + use \Imi\Util\Traits\TStaticClass; + /** * 缓存处理器数组. * @@ -22,10 +24,6 @@ class CacheManager */ protected static bool $inited = false; - private function __construct() - { - } - public static function init(): void { foreach (Config::getAliases() as $alias) diff --git a/src/Cli/ArgType.php b/src/Cli/ArgType.php index badcdede57..d9c8ac7a0d 100644 --- a/src/Cli/ArgType.php +++ b/src/Cli/ArgType.php @@ -9,6 +9,8 @@ */ class ArgType { + use \Imi\Util\Traits\TStaticClass; + public const STRING = 'string'; public const INT = 'int'; @@ -31,10 +33,6 @@ class ArgType public const MIXED = 'mixed'; - private function __construct() - { - } - public static function isBooleanType(string $type): bool { return self::BOOLEAN === $type || self::BOOLEAN_NEGATABLE === $type || self::MIXED === $type; diff --git a/src/Cli/CliAppContexts.php b/src/Cli/CliAppContexts.php index c847a6682e..bae4c9c8e4 100644 --- a/src/Cli/CliAppContexts.php +++ b/src/Cli/CliAppContexts.php @@ -9,12 +9,10 @@ */ class CliAppContexts { + use \Imi\Util\Traits\TStaticClass; + /** * 命令行名称. */ public const COMMAND_NAME = 'command_name'; - - private function __construct() - { - } } diff --git a/src/Cli/CliManager.php b/src/Cli/CliManager.php index bab1f1dbd3..b391e7d5f9 100644 --- a/src/Cli/CliManager.php +++ b/src/Cli/CliManager.php @@ -9,14 +9,12 @@ */ class CliManager { + use \Imi\Util\Traits\TStaticClass; + private static array $map = []; private static array $commandActionMap = []; - private function __construct() - { - } - public static function getMap(): array { return self::$map; diff --git a/src/Components/access-control/src/AccessControl/Operation.php b/src/Components/access-control/src/AccessControl/Operation.php index 9d8d6e41c2..7ed3f1993c 100644 --- a/src/Components/access-control/src/AccessControl/Operation.php +++ b/src/Components/access-control/src/AccessControl/Operation.php @@ -6,8 +6,10 @@ use Imi\App; -abstract class Operation +class Operation { + use \Imi\Util\Traits\TStaticClass; + /** * 创建操作权限. */ diff --git a/src/Components/amqp/example/bin/start-server.sh b/src/Components/amqp/example/bin/start-server.sh index 168fc140c7..f764674b77 100755 --- a/src/Components/amqp/example/bin/start-server.sh +++ b/src/Components/amqp/example/bin/start-server.sh @@ -6,4 +6,14 @@ rm -rf ${__DIR__}/../.runtime/*runtime ${__DIR__}/stop-server.sh $1 -nohup $__DIR__/imi-$1 $1/start > "$__DIR__/../.runtime/logs/$1.log" 2>&1 & echo $! > "$__DIR__/server.pid" +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi-$1 $1/start > "$__DIR__/../.runtime/logs/$1.log" 2>&1 & echo $! > "$__DIR__/server.pid" diff --git a/src/Components/amqp/example/bin/stop-server.sh b/src/Components/amqp/example/bin/stop-server.sh index acd429296f..264a660a30 100755 --- a/src/Components/amqp/example/bin/stop-server.sh +++ b/src/Components/amqp/example/bin/stop-server.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -$__DIR__/imi-$1 $1/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi-$1 $1/stop diff --git a/src/Components/amqp/example/config/config.php b/src/Components/amqp/example/config/config.php index bf0ec28827..e6473ba94f 100644 --- a/src/Components/amqp/example/config/config.php +++ b/src/Components/amqp/example/config/config.php @@ -43,6 +43,7 @@ 'port' => 8080, 'configs' => [ 'worker_num' => 1, + 'max_wait_time' => 30, ], ], @@ -58,6 +59,12 @@ ], ], + 'workerman' => [ + 'worker' => [ + 'stopTimeout' => 30, + ], + ], + // 子服务器(端口监听)配置 'subServers' => [ ], diff --git a/src/Components/amqp/src/Enum/ConsumerResult.php b/src/Components/amqp/src/Enum/ConsumerResult.php index e007b99bcd..174a2c9cf5 100644 --- a/src/Components/amqp/src/Enum/ConsumerResult.php +++ b/src/Components/amqp/src/Enum/ConsumerResult.php @@ -10,8 +10,10 @@ /** * 消费者执行结果. */ -abstract class ConsumerResult extends BaseEnum +class ConsumerResult extends BaseEnum { + use \Imi\Util\Traits\TStaticClass; + /** * 用于消息消费成功 * diff --git a/src/Components/amqp/src/Pool/AMQPPool.php b/src/Components/amqp/src/Pool/AMQPPool.php index 730cce5568..2b718ba4aa 100644 --- a/src/Components/amqp/src/Pool/AMQPPool.php +++ b/src/Components/amqp/src/Pool/AMQPPool.php @@ -16,15 +16,13 @@ */ class AMQPPool { + use \Imi\Util\Traits\TStaticClass; + /** * 连接配置. */ private static ?array $connections = null; - private function __construct() - { - } - /** * 获取新的连接实例. */ diff --git a/src/Components/amqp/tests/bin/checkPorts.php b/src/Components/amqp/tests/bin/checkPorts.php deleted file mode 100644 index f9e04c2244..0000000000 --- a/src/Components/amqp/tests/bin/checkPorts.php +++ /dev/null @@ -1,35 +0,0 @@ -= 10) - { - echo 'failed', \PHP_EOL; - continue 2; - } - ++$count; - sleep(1); - } - echo 'OK', \PHP_EOL; -} diff --git a/src/Components/amqp/tests/bootstrap.php b/src/Components/amqp/tests/bootstrap.php index f6cca7389d..ceda80e14b 100644 --- a/src/Components/amqp/tests/bootstrap.php +++ b/src/Components/amqp/tests/bootstrap.php @@ -3,7 +3,6 @@ declare(strict_types=1); use function Imi\env; -use function Imi\ttyExec; use function Yurun\Swoole\Coroutine\batch; require \dirname(__DIR__) . '/vendor/autoload.php'; @@ -18,7 +17,7 @@ function checkHttpServerStatus() sleep(1); try { - $context = stream_context_create(['http' => ['timeout' => 1]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); $body = @file_get_contents('http://127.0.0.1:8080/', false, $context); if ('imi' === $body) { @@ -86,8 +85,7 @@ function startServer() batch($callbacks, 120, max(swoole_cpu_num() - 1, 1)); register_shutdown_function(static function () { - echo 'check ports...', \PHP_EOL; - ttyExec(\PHP_BINARY . ' ' . __DIR__ . '/bin/checkPorts.php'); + checkPorts([8080]); }); } diff --git a/src/Components/apidoc/example/bin/start-server.sh b/src/Components/apidoc/example/bin/start-server.sh index 89235390dd..74d64053ec 100755 --- a/src/Components/apidoc/example/bin/start-server.sh +++ b/src/Components/apidoc/example/bin/start-server.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop-server.sh -nohup $__DIR__/imi swoole/start > "$__DIR__/../.runtime/logs/cli.log" 2>&1 & echo $! > "$__DIR__/server.pid" +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi swoole/start > "$__DIR__/../.runtime/logs/cli.log" 2>&1 & echo $! > "$__DIR__/server.pid" diff --git a/src/Components/apidoc/example/bin/stop-server.sh b/src/Components/apidoc/example/bin/stop-server.sh index e0fd6706c4..5096745bad 100755 --- a/src/Components/apidoc/example/bin/stop-server.sh +++ b/src/Components/apidoc/example/bin/stop-server.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -$__DIR__/imi swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi swoole/stop diff --git a/src/Components/apidoc/example/config/config.php b/src/Components/apidoc/example/config/config.php index 004ba0e614..36b509636f 100644 --- a/src/Components/apidoc/example/config/config.php +++ b/src/Components/apidoc/example/config/config.php @@ -26,6 +26,7 @@ 'port' => 8080, 'configs' => [ 'worker_num' => 1, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/fpm/src/FpmAppContexts.php b/src/Components/fpm/src/FpmAppContexts.php index 5926073bb4..1e0166b813 100644 --- a/src/Components/fpm/src/FpmAppContexts.php +++ b/src/Components/fpm/src/FpmAppContexts.php @@ -6,12 +6,10 @@ class FpmAppContexts { + use \Imi\Util\Traits\TStaticClass; + /** * 进程类型. */ public const ROUTE_INITED = 'fpm_route_inited'; - - private function __construct() - { - } } diff --git a/src/Components/fpm/src/Server/Type.php b/src/Components/fpm/src/Server/Type.php index 7be5e16186..5603ffc1a4 100644 --- a/src/Components/fpm/src/Server/Type.php +++ b/src/Components/fpm/src/Server/Type.php @@ -6,12 +6,10 @@ class Type { + use \Imi\Util\Traits\TStaticClass; + /** * HTTP服务器. */ public const HTTP = 'FpmHttpServer'; - - private function __construct() - { - } } diff --git a/src/Components/fpm/tests/HttpServer/bin/start.sh b/src/Components/fpm/tests/HttpServer/bin/start.sh index ba35cd71b8..a800be0a32 100755 --- a/src/Components/fpm/tests/HttpServer/bin/start.sh +++ b/src/Components/fpm/tests/HttpServer/bin/start.sh @@ -4,9 +4,18 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -if [[ "$1" = "-d" ]]; then - nohup /usr/bin/env php -d request_order=CGP -t "$__DIR__/../../Web/public" -S 127.0.0.1:13000 > "$__DIR__/../logs/cli.log" 2>&1 & echo $! > "$__DIR__/server.pid" +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" else - /usr/bin/env php -d request_order=CGP -t "$__DIR__/../../Web/public" -S 127.0.0.1:13000 + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi fi +if [[ "$1" = "-d" ]]; then + nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage -d request_order=CGP -t "$__DIR__/../../Web/public" -S 127.0.0.1:13000 > "$__DIR__/../logs/cli.log" 2>&1 & echo $! > "$__DIR__/server.pid" +else + /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage -d request_order=CGP -t "$__DIR__/../../Web/public" -S 127.0.0.1:13000 +fi diff --git a/src/Components/fpm/tests/bin/checkPorts.php b/src/Components/fpm/tests/bin/checkPorts.php deleted file mode 100644 index 0777ae6b62..0000000000 --- a/src/Components/fpm/tests/bin/checkPorts.php +++ /dev/null @@ -1,35 +0,0 @@ -= 10) - { - echo 'failed', \PHP_EOL; - continue 2; - } - ++$count; - sleep(1); - } - echo 'OK', \PHP_EOL; -} diff --git a/src/Components/fpm/tests/bootstrap.php b/src/Components/fpm/tests/bootstrap.php index 59941b23f0..55b7c53258 100644 --- a/src/Components/fpm/tests/bootstrap.php +++ b/src/Components/fpm/tests/bootstrap.php @@ -3,7 +3,6 @@ declare(strict_types=1); use function Imi\env; -use function Imi\ttyExec; require \dirname(__DIR__) . '/vendor/autoload.php'; @@ -19,7 +18,7 @@ function checkHttpServerStatus(): bool for ($i = 0; $i < 20; ++$i) { sleep(1); - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); if ('imi' === @file_get_contents(env('HTTP_SERVER_HOST', 'http://127.0.0.1:13000/'), false, $context)) { $serverStarted = true; @@ -87,8 +86,7 @@ function checkHttpServerStatus(): bool } } register_shutdown_function(static function () { - echo 'check ports...', \PHP_EOL; - ttyExec(\PHP_BINARY . ' ' . __DIR__ . '/bin/checkPorts.php'); + checkPorts([13000]); }); } diff --git a/src/Components/grpc/example/Task/TestTask.php b/src/Components/grpc/example/Task/TestTask.php deleted file mode 100644 index 291a4b1ac3..0000000000 --- a/src/Components/grpc/example/Task/TestTask.php +++ /dev/null @@ -1,32 +0,0 @@ -getData(); - - return date('Y-m-d H:i:s', $data['time']); - } - - /** - * {@inheritDoc} - */ - public function finish(\Swoole\Server $server, int $taskId, $data): void - { - } -} diff --git a/src/Components/grpc/example/bin/start-server.sh b/src/Components/grpc/example/bin/start-server.sh index 89235390dd..74d64053ec 100755 --- a/src/Components/grpc/example/bin/start-server.sh +++ b/src/Components/grpc/example/bin/start-server.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop-server.sh -nohup $__DIR__/imi swoole/start > "$__DIR__/../.runtime/logs/cli.log" 2>&1 & echo $! > "$__DIR__/server.pid" +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi swoole/start > "$__DIR__/../.runtime/logs/cli.log" 2>&1 & echo $! > "$__DIR__/server.pid" diff --git a/src/Components/grpc/example/bin/stop-server.sh b/src/Components/grpc/example/bin/stop-server.sh index e0fd6706c4..5096745bad 100755 --- a/src/Components/grpc/example/bin/stop-server.sh +++ b/src/Components/grpc/example/bin/stop-server.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -$__DIR__/imi swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi swoole/stop diff --git a/src/Components/grpc/example/config/beans.php b/src/Components/grpc/example/config/beans.php index b2308836b2..532754a42c 100644 --- a/src/Components/grpc/example/config/beans.php +++ b/src/Components/grpc/example/config/beans.php @@ -6,7 +6,7 @@ return [ 'hotUpdate' => [ - // 'status' => false, // 关闭热更新去除注释,不设置即为开启,建议生产环境关闭 + 'status' => false, // 关闭热更新去除注释,不设置即为开启,建议生产环境关闭 // --- 文件修改时间监控 --- // 'monitorClass' => \Imi\HotUpdate\Monitor\FileMTime::class, diff --git a/src/Components/grpc/example/config/config.php b/src/Components/grpc/example/config/config.php index e15495c54c..2d88f41f0b 100644 --- a/src/Components/grpc/example/config/config.php +++ b/src/Components/grpc/example/config/config.php @@ -18,7 +18,6 @@ // 扫描目录 'beanScan' => [ 'GrpcApp\Listener', - 'GrpcApp\Task', ], // 组件命名空间 @@ -40,6 +39,7 @@ 'port' => 8080, 'configs' => [ 'worker_num' => 1, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/grpc/src/Enum/GrpcStatus.php b/src/Components/grpc/src/Enum/GrpcStatus.php index e349eaaf76..11ff1ad986 100644 --- a/src/Components/grpc/src/Enum/GrpcStatus.php +++ b/src/Components/grpc/src/Enum/GrpcStatus.php @@ -7,8 +7,10 @@ /** * 参考:https://grpc.github.io/grpc/core/md_doc_statuscodes.html. */ -abstract class GrpcStatus +class GrpcStatus { + use \Imi\Util\Traits\TStaticClass; + /** * Not an error; returned on success. */ diff --git a/src/Components/grpc/src/Parser.php b/src/Components/grpc/src/Parser.php index 20c9aba8e0..f6c6daf96b 100644 --- a/src/Components/grpc/src/Parser.php +++ b/src/Components/grpc/src/Parser.php @@ -11,8 +11,10 @@ * * 参考实现:https://www.jianshu.com/p/f3221df39e6f */ -abstract class Parser +class Parser { + use \Imi\Util\Traits\TStaticClass; + public static function pack(string $data): string { return $data = pack('CN', 0, \strlen($data)) . $data; diff --git a/src/Components/grpc/tests/bin/checkPorts.php b/src/Components/grpc/tests/bin/checkPorts.php deleted file mode 100644 index 07ddd5d89f..0000000000 --- a/src/Components/grpc/tests/bin/checkPorts.php +++ /dev/null @@ -1,35 +0,0 @@ -= 10) - { - echo 'failed', \PHP_EOL; - continue 2; - } - ++$count; - sleep(1); - } - echo 'OK', \PHP_EOL; -} diff --git a/src/Components/grpc/tests/bootstrap.php b/src/Components/grpc/tests/bootstrap.php index e91e89bf71..79e34dfaa9 100644 --- a/src/Components/grpc/tests/bootstrap.php +++ b/src/Components/grpc/tests/bootstrap.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use function Imi\ttyExec; use function Yurun\Swoole\Coroutine\batch; require \dirname(__DIR__) . '/vendor/autoload.php'; @@ -17,7 +16,7 @@ function checkHttpServerStatus() sleep(1); try { - $context = stream_context_create(['http' => ['timeout' => 1]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); if ('' === @file_get_contents('http://127.0.0.1:8081/', false, $context)) { return true; @@ -78,8 +77,7 @@ function startServer() batch($callbacks, 120, max(swoole_cpu_num() - 1, 1)); register_shutdown_function(static function () { - echo 'check ports...', \PHP_EOL; - ttyExec(\PHP_BINARY . ' ' . __DIR__ . '/bin/checkPorts.php'); + checkPorts([8081]); }); } diff --git a/src/Components/kafka/example/bin/start-server.sh b/src/Components/kafka/example/bin/start-server.sh index 168fc140c7..f764674b77 100755 --- a/src/Components/kafka/example/bin/start-server.sh +++ b/src/Components/kafka/example/bin/start-server.sh @@ -6,4 +6,14 @@ rm -rf ${__DIR__}/../.runtime/*runtime ${__DIR__}/stop-server.sh $1 -nohup $__DIR__/imi-$1 $1/start > "$__DIR__/../.runtime/logs/$1.log" 2>&1 & echo $! > "$__DIR__/server.pid" +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi-$1 $1/start > "$__DIR__/../.runtime/logs/$1.log" 2>&1 & echo $! > "$__DIR__/server.pid" diff --git a/src/Components/kafka/example/bin/stop-server.sh b/src/Components/kafka/example/bin/stop-server.sh index acd429296f..264a660a30 100755 --- a/src/Components/kafka/example/bin/stop-server.sh +++ b/src/Components/kafka/example/bin/stop-server.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -$__DIR__/imi-$1 $1/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi-$1 $1/stop diff --git a/src/Components/kafka/example/config/config.php b/src/Components/kafka/example/config/config.php index 82604c823b..bfec71aaf8 100644 --- a/src/Components/kafka/example/config/config.php +++ b/src/Components/kafka/example/config/config.php @@ -41,6 +41,7 @@ 'port' => 8080, 'configs' => [ 'worker_num' => 1, + 'max_wait_time' => 30, ], ], @@ -56,6 +57,12 @@ ], ], + 'workerman' => [ + 'worker' => [ + 'stopTimeout' => 30, + ], + ], + // 子服务器(端口监听)配置 'subServers' => [ ], diff --git a/src/Components/kafka/src/Pool/KafkaPool.php b/src/Components/kafka/src/Pool/KafkaPool.php index 77e5bc0f7c..efe71be36f 100644 --- a/src/Components/kafka/src/Pool/KafkaPool.php +++ b/src/Components/kafka/src/Pool/KafkaPool.php @@ -140,7 +140,17 @@ public static function createConsumerConfig(array $config = []): ConsumerConfig $config['maxWait'] = 10; } - return new ConsumerConfig($config); + $consumerConfig = new ConsumerConfig(); + foreach ($config as $k => $v) + { + $methodName = 'set' . ucfirst($k); + if (method_exists(ConsumerConfig::class, $methodName)) + { + $consumerConfig->{$methodName}($v); + } + } + + return $consumerConfig; } public static function createProducerConfig(array $config = []): ProducerConfig @@ -150,12 +160,18 @@ public static function createProducerConfig(array $config = []): ProducerConfig { $config['clientId'] = $clientId; } - if (!isset($config['groupInstanceId'])) + + $producerConfig = new ProducerConfig(); + foreach ($config as $k => $v) { - $config['groupInstanceId'] = $clientId; + $methodName = 'set' . ucfirst($k); + if (method_exists(ProducerConfig::class, $methodName)) + { + $producerConfig->{$methodName}($v); + } } - return new ProducerConfig($config); + return $producerConfig; } /** diff --git a/src/Components/kafka/tests/bin/checkPorts.php b/src/Components/kafka/tests/bin/checkPorts.php deleted file mode 100644 index f9e04c2244..0000000000 --- a/src/Components/kafka/tests/bin/checkPorts.php +++ /dev/null @@ -1,35 +0,0 @@ -= 10) - { - echo 'failed', \PHP_EOL; - continue 2; - } - ++$count; - sleep(1); - } - echo 'OK', \PHP_EOL; -} diff --git a/src/Components/kafka/tests/bootstrap.php b/src/Components/kafka/tests/bootstrap.php index 0923b6c922..2bef3e54f9 100644 --- a/src/Components/kafka/tests/bootstrap.php +++ b/src/Components/kafka/tests/bootstrap.php @@ -3,7 +3,6 @@ declare(strict_types=1); use function Imi\env; -use function Imi\ttyExec; use function Yurun\Swoole\Coroutine\batch; require \dirname(__DIR__) . '/vendor/autoload.php'; @@ -18,7 +17,7 @@ function checkHttpServerStatus() sleep(1); try { - $context = stream_context_create(['http' => ['timeout' => 1]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); $body = @file_get_contents('http://127.0.0.1:8080/', false, $context); if ('imi' === $body) { @@ -85,8 +84,7 @@ function startServer() batch($callbacks, 120, max(swoole_cpu_num() - 1, 1)); register_shutdown_function(static function () { - echo 'check ports...', \PHP_EOL; - ttyExec(\PHP_BINARY . ' ' . __DIR__ . '/bin/checkPorts.php'); + checkPorts([8080]); }); } diff --git a/src/Components/macro/src/MacroComposerHook.php b/src/Components/macro/src/MacroComposerHook.php index fcf111fda5..7ee7a6bada 100644 --- a/src/Components/macro/src/MacroComposerHook.php +++ b/src/Components/macro/src/MacroComposerHook.php @@ -8,9 +8,7 @@ class MacroComposerHook { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; public static function hookComposer(): void { diff --git a/src/Components/mqtt/example/bin/start-server.sh b/src/Components/mqtt/example/bin/start-server.sh index 89235390dd..74d64053ec 100755 --- a/src/Components/mqtt/example/bin/start-server.sh +++ b/src/Components/mqtt/example/bin/start-server.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop-server.sh -nohup $__DIR__/imi swoole/start > "$__DIR__/../.runtime/logs/cli.log" 2>&1 & echo $! > "$__DIR__/server.pid" +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi swoole/start > "$__DIR__/../.runtime/logs/cli.log" 2>&1 & echo $! > "$__DIR__/server.pid" diff --git a/src/Components/mqtt/example/bin/stop-server.sh b/src/Components/mqtt/example/bin/stop-server.sh index e0fd6706c4..5096745bad 100755 --- a/src/Components/mqtt/example/bin/stop-server.sh +++ b/src/Components/mqtt/example/bin/stop-server.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -$__DIR__/imi swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi swoole/stop diff --git a/src/Components/mqtt/example/config/beans.php b/src/Components/mqtt/example/config/beans.php index b2308836b2..532754a42c 100644 --- a/src/Components/mqtt/example/config/beans.php +++ b/src/Components/mqtt/example/config/beans.php @@ -6,7 +6,7 @@ return [ 'hotUpdate' => [ - // 'status' => false, // 关闭热更新去除注释,不设置即为开启,建议生产环境关闭 + 'status' => false, // 关闭热更新去除注释,不设置即为开启,建议生产环境关闭 // --- 文件修改时间监控 --- // 'monitorClass' => \Imi\HotUpdate\Monitor\FileMTime::class, diff --git a/src/Components/mqtt/example/config/config.php b/src/Components/mqtt/example/config/config.php index 038b424629..ca4a65bd55 100644 --- a/src/Components/mqtt/example/config/config.php +++ b/src/Components/mqtt/example/config/config.php @@ -33,6 +33,7 @@ 'port' => 8081, 'configs' => [ 'worker_num' => 1, + 'max_wait_time' => 30, ], 'controller' => \MQTTApp\MQTTServer\Controller\MQTTController::class, ], diff --git a/src/Components/mqtt/tests/bin/checkPorts.php b/src/Components/mqtt/tests/bin/checkPorts.php deleted file mode 100644 index aba4c63607..0000000000 --- a/src/Components/mqtt/tests/bin/checkPorts.php +++ /dev/null @@ -1,35 +0,0 @@ -= 10) - { - echo 'failed', \PHP_EOL; - continue 2; - } - ++$count; - sleep(1); - } - echo 'OK', \PHP_EOL; -} diff --git a/src/Components/mqtt/tests/bootstrap.php b/src/Components/mqtt/tests/bootstrap.php index 002752e1d2..5262fe3d85 100644 --- a/src/Components/mqtt/tests/bootstrap.php +++ b/src/Components/mqtt/tests/bootstrap.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use function Imi\ttyExec; use function Yurun\Swoole\Coroutine\batch; require \dirname(__DIR__) . '/vendor/autoload.php'; @@ -82,8 +81,7 @@ function startServer() batch($callbacks, 120, max(swoole_cpu_num() - 1, 1)); register_shutdown_function(static function () { - echo 'check ports...', \PHP_EOL; - ttyExec(\PHP_BINARY . ' ' . __DIR__ . '/bin/checkPorts.php'); + checkPorts([8081, 8082]); }); } diff --git a/src/Components/pgsql/src/Db/Drivers/Swoole/Driver.php b/src/Components/pgsql/src/Db/Drivers/Swoole/Driver.php index da4c4d46e3..84368bd7de 100644 --- a/src/Components/pgsql/src/Db/Drivers/Swoole/Driver.php +++ b/src/Components/pgsql/src/Db/Drivers/Swoole/Driver.php @@ -220,13 +220,13 @@ public function commit(): bool */ public function rollBack(?int $levels = null): bool { - if (null === $levels) + if (null === $levels || ($toLevel = $this->getTransactionLevels() - $levels) <= 0) { $result = $this->instance->query('rollback'); } else { - $this->exec('ROLLBACK TO P' . $this->getTransactionLevels()); + $this->exec('ROLLBACK TO P' . $toLevel); $result = true; } if ($result) diff --git a/src/Components/pgsql/src/Db/Drivers/SwooleNew/Driver.php b/src/Components/pgsql/src/Db/Drivers/SwooleNew/Driver.php index d12f1f2524..a0a13368e3 100644 --- a/src/Components/pgsql/src/Db/Drivers/SwooleNew/Driver.php +++ b/src/Components/pgsql/src/Db/Drivers/SwooleNew/Driver.php @@ -213,13 +213,13 @@ public function commit(): bool */ public function rollBack(?int $levels = null): bool { - if (null === $levels) + if (null === $levels || ($toLevel = $this->getTransactionLevels() - $levels) <= 0) { $result = $this->instance->query('rollback'); } else { - $this->exec('ROLLBACK TO P' . $this->getTransactionLevels()); + $this->exec('ROLLBACK TO P' . $toLevel); $result = true; } if ($result) diff --git a/src/Components/pgsql/src/Db/Query/PgsqlQuery.php b/src/Components/pgsql/src/Db/Query/PgsqlQuery.php index a9b7895895..d44389b2ff 100644 --- a/src/Components/pgsql/src/Db/Query/PgsqlQuery.php +++ b/src/Components/pgsql/src/Db/Query/PgsqlQuery.php @@ -88,6 +88,10 @@ public function parseKeywordText(string $string): array */ public function parseKeywordToText(array $keywords, ?string $alias = null, ?array $jsonKeywords = null): string { + if (!$keywords) + { + return ''; + } foreach ($keywords as $k => $v) { if (Text::isEmpty($v)) @@ -95,6 +99,11 @@ public function parseKeywordToText(array $keywords, ?string $alias = null, ?arra unset($keywords[$k]); } } + // @phpstan-ignore-next-line + if (!$keywords) + { + return ''; + } $isLastStar = '*' === end($keywords); $result = '"' . implode('"."', $keywords) . '"'; if ($isLastStar) diff --git a/src/Components/pgsql/src/Db/Util/SqlUtil.php b/src/Components/pgsql/src/Db/Util/SqlUtil.php index e5d4799e29..c74ae1938b 100644 --- a/src/Components/pgsql/src/Db/Util/SqlUtil.php +++ b/src/Components/pgsql/src/Db/Util/SqlUtil.php @@ -13,9 +13,7 @@ */ class SqlUtil { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 解析带参数的 SQL,返回解析后的 SQL. diff --git a/src/Components/phar/tests/project/config/config.php b/src/Components/phar/tests/project/config/config.php index 03bbca8e51..c9afc4751b 100644 --- a/src/Components/phar/tests/project/config/config.php +++ b/src/Components/phar/tests/project/config/config.php @@ -30,7 +30,8 @@ 'host' => '0.0.0.0', 'port' => 13000, 'configs' => [ - 'log_file' => app_real_root_path() . '/.runtime/swoole/swoole.log', + 'log_file' => app_real_root_path() . '/.runtime/swoole/swoole.log', + 'max_wait_time' => 30, // 'worker_num' => 8, // 'task_worker_num' => 16, ], @@ -58,6 +59,12 @@ ], ] : [], + 'workerman' => [ + 'worker' => [ + 'stopTimeout' => 30, + ], + ], + // fpm 服务器配置 'fpm' => 'fpm' === $mode ? [ 'serverPath' => \dirname(__DIR__) . '/ApiServer', diff --git a/src/Components/phar/tests/run-tests.php b/src/Components/phar/tests/run-tests.php index 1ea87b1b3e..676ccf72a1 100644 --- a/src/Components/phar/tests/run-tests.php +++ b/src/Components/phar/tests/run-tests.php @@ -133,7 +133,7 @@ try { echo '> Wait running', \PHP_EOL; - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); $count = 0; while ($testServer->isRunning() && $count++ < STARTUP_MAX_WAIT) { diff --git a/src/Components/queue/example/config/beans.php b/src/Components/queue/example/config/beans.php index 050e40d808..608d8dfe4a 100644 --- a/src/Components/queue/example/config/beans.php +++ b/src/Components/queue/example/config/beans.php @@ -6,7 +6,7 @@ return [ 'hotUpdate' => [ - // 'status' => false, // 关闭热更新去除注释,不设置即为开启,建议生产环境关闭 + 'status' => false, // 关闭热更新去除注释,不设置即为开启,建议生产环境关闭 // --- 文件修改时间监控 --- // 'monitorClass' => \Imi\HotUpdate\Monitor\FileMTime::class, diff --git a/src/Components/queue/example/config/config.php b/src/Components/queue/example/config/config.php index 0769bc71ad..ced979d911 100644 --- a/src/Components/queue/example/config/config.php +++ b/src/Components/queue/example/config/config.php @@ -36,6 +36,7 @@ 'port' => 8080, 'configs' => [ 'worker_num' => 1, + 'max_wait_time' => 30, ], ], @@ -51,6 +52,12 @@ ], ], + 'workerman' => [ + 'worker' => [ + 'stopTimeout' => 30, + ], + ], + // 连接池配置 'pools' => Imi::checkAppType('swoole') ? [ 'redis' => [ diff --git a/src/Components/queue/src/Enum/QueueType.php b/src/Components/queue/src/Enum/QueueType.php index 5cda79d289..bf09b3f6d9 100644 --- a/src/Components/queue/src/Enum/QueueType.php +++ b/src/Components/queue/src/Enum/QueueType.php @@ -10,8 +10,10 @@ /** * 队列类型. */ -abstract class QueueType extends BaseEnum +class QueueType extends BaseEnum { + use \Imi\Util\Traits\TStaticClass; + /** * @EnumItem(text="准备就绪", type="list") */ diff --git a/src/Components/rate-limit/src/RateLimiter.php b/src/Components/rate-limit/src/RateLimiter.php index e8b0a6cb30..de374f97a9 100644 --- a/src/Components/rate-limit/src/RateLimiter.php +++ b/src/Components/rate-limit/src/RateLimiter.php @@ -15,8 +15,10 @@ /** * 限流器手动调用类. */ -abstract class RateLimiter +class RateLimiter { + use \Imi\Util\Traits\TStaticClass; + /** * 限流 * diff --git a/src/Components/rate-limit/src/WorkerLimiter.php b/src/Components/rate-limit/src/WorkerLimiter.php index 05f393b644..a01a281d56 100644 --- a/src/Components/rate-limit/src/WorkerLimiter.php +++ b/src/Components/rate-limit/src/WorkerLimiter.php @@ -9,8 +9,10 @@ /** * 并发工作数限流器手动调用类. */ -abstract class WorkerLimiter +class WorkerLimiter { + use \Imi\Util\Traits\TStaticClass; + /** * 限流执行任务 * diff --git a/src/Components/rate-limit/src/WorkerLimiterLock.php b/src/Components/rate-limit/src/WorkerLimiterLock.php index bd53f9a179..4229e1755a 100644 --- a/src/Components/rate-limit/src/WorkerLimiterLock.php +++ b/src/Components/rate-limit/src/WorkerLimiterLock.php @@ -8,8 +8,10 @@ use Imi\Redis\RedisHandler; use Imi\Redis\RedisManager; -abstract class WorkerLimiterLock +class WorkerLimiterLock { + use \Imi\Util\Traits\TStaticClass; + /** * @return mixed */ diff --git a/src/Components/roadrunner/src/Server/Type.php b/src/Components/roadrunner/src/Server/Type.php index ffb1724ba8..8eedfd8758 100644 --- a/src/Components/roadrunner/src/Server/Type.php +++ b/src/Components/roadrunner/src/Server/Type.php @@ -6,12 +6,10 @@ class Type { + use \Imi\Util\Traits\TStaticClass; + /** * HTTP服务器. */ public const HTTP = 'RoadRunnerHttpServer'; - - private function __construct() - { - } } diff --git a/src/Components/roadrunner/src/Util/RoadRunner.php b/src/Components/roadrunner/src/Util/RoadRunner.php index f4ccb4fb17..18c12fd7a3 100644 --- a/src/Components/roadrunner/src/Util/RoadRunner.php +++ b/src/Components/roadrunner/src/Util/RoadRunner.php @@ -8,9 +8,7 @@ class RoadRunner { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 获取 RoadRunner 二进制文件路径. diff --git a/src/Components/roadrunner/tests/bootstrap.php b/src/Components/roadrunner/tests/bootstrap.php index 93abb6e2e4..68c7341afd 100644 --- a/src/Components/roadrunner/tests/bootstrap.php +++ b/src/Components/roadrunner/tests/bootstrap.php @@ -18,7 +18,7 @@ function checkHttpServerStatus(): bool for ($i = 0; $i < 20; ++$i) { sleep(1); - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); if ('imi' === @file_get_contents(env('HTTP_SERVER_HOST', 'http://127.0.0.1:13000/'), false, $context)) { $serverStarted = true; diff --git a/src/Components/roadrunner/tests/unit/HttpServer/bin/start.sh b/src/Components/roadrunner/tests/unit/HttpServer/bin/start.sh index 91f62a4e29..5ff26139c0 100755 --- a/src/Components/roadrunner/tests/unit/HttpServer/bin/start.sh +++ b/src/Components/roadrunner/tests/unit/HttpServer/bin/start.sh @@ -4,8 +4,18 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + if [[ "$1" = "-d" ]]; then - nohup /usr/bin/env php "$__DIR__/cli" rr/start --app-namespace "Imi\RoadRunner\Test\HttpServer" -w "$__DIR__/../" 2>&1 & + nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/cli" rr/start --app-namespace "Imi\RoadRunner\Test\HttpServer" -w "$__DIR__/../" 2>&1 & else - /usr/bin/env php "$__DIR__/cli" rr/start --app-namespace "Imi\RoadRunner\Test\HttpServer" -w "$__DIR__/../" + /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/cli" rr/start --app-namespace "Imi\RoadRunner\Test\HttpServer" -w "$__DIR__/../" fi diff --git a/src/Components/roadrunner/tests/unit/HttpServer/bin/stop.sh b/src/Components/roadrunner/tests/unit/HttpServer/bin/stop.sh index 3c497ce994..6817f9f79b 100755 --- a/src/Components/roadrunner/tests/unit/HttpServer/bin/stop.sh +++ b/src/Components/roadrunner/tests/unit/HttpServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -php "$__DIR__/cli" rr/stop --app-namespace "Imi\RoadRunner\Test\HttpServer" -w "$__DIR__/../" +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/cli" rr/stop --app-namespace "Imi\RoadRunner\Test\HttpServer" -w "$__DIR__/../" diff --git a/src/Components/shared-memory/src/SharedMemory.php b/src/Components/shared-memory/src/SharedMemory.php index b2fb798898..f5b4637d04 100644 --- a/src/Components/shared-memory/src/SharedMemory.php +++ b/src/Components/shared-memory/src/SharedMemory.php @@ -8,8 +8,10 @@ use Imi\Pool\PoolManager; use Imi\RequestContext; -abstract class SharedMemory +class SharedMemory { + use \Imi\Util\Traits\TStaticClass; + /** * 获取新的内存共享连接实例. * diff --git a/src/Components/smarty/example/bin/start.sh b/src/Components/smarty/example/bin/start.sh index f7b5913a08..dc99df3514 100755 --- a/src/Components/smarty/example/bin/start.sh +++ b/src/Components/smarty/example/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup $__DIR__/imi swoole/start > "$__DIR__/../.runtime/logs/cli.log" 2>&1 & echo $! > "$__DIR__/server.pid" +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage $__DIR__/imi swoole/start > "$__DIR__/../.runtime/logs/cli.log" 2>&1 & echo $! > "$__DIR__/server.pid" diff --git a/src/Components/smarty/example/bin/stop.sh b/src/Components/smarty/example/bin/stop.sh index 3aa035b58f..b1abd27d1f 100755 --- a/src/Components/smarty/example/bin/stop.sh +++ b/src/Components/smarty/example/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/smarty/example/config/beans.php b/src/Components/smarty/example/config/beans.php index b2308836b2..532754a42c 100644 --- a/src/Components/smarty/example/config/beans.php +++ b/src/Components/smarty/example/config/beans.php @@ -6,7 +6,7 @@ return [ 'hotUpdate' => [ - // 'status' => false, // 关闭热更新去除注释,不设置即为开启,建议生产环境关闭 + 'status' => false, // 关闭热更新去除注释,不设置即为开启,建议生产环境关闭 // --- 文件修改时间监控 --- // 'monitorClass' => \Imi\HotUpdate\Monitor\FileMTime::class, diff --git a/src/Components/smarty/example/config/config.php b/src/Components/smarty/example/config/config.php index 276378fb13..47e6c14ff5 100644 --- a/src/Components/smarty/example/config/config.php +++ b/src/Components/smarty/example/config/config.php @@ -34,6 +34,7 @@ 'configs' => [ 'worker_num' => 1, 'task_worker_num' => 1, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/smarty/tests/bin/checkPorts.php b/src/Components/smarty/tests/bin/checkPorts.php deleted file mode 100644 index cd6c58b007..0000000000 --- a/src/Components/smarty/tests/bin/checkPorts.php +++ /dev/null @@ -1,35 +0,0 @@ -= 10) - { - echo 'failed', \PHP_EOL; - continue 2; - } - ++$count; - sleep(1); - } - echo 'OK', \PHP_EOL; -} diff --git a/src/Components/smarty/tests/bootstrap.php b/src/Components/smarty/tests/bootstrap.php index 37cea94f6a..c2736789f3 100644 --- a/src/Components/smarty/tests/bootstrap.php +++ b/src/Components/smarty/tests/bootstrap.php @@ -2,8 +2,6 @@ declare(strict_types=1); -use function Imi\ttyExec; - require \dirname(__DIR__) . '/vendor/autoload.php'; function checkHttpServerStatus(): bool @@ -13,7 +11,7 @@ function checkHttpServerStatus(): bool sleep(1); try { - $context = stream_context_create(['http' => ['timeout' => 1]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); $body = @file_get_contents('http://127.0.0.1:13456/ping', false, $context); if ('pong' === $body) { @@ -66,8 +64,7 @@ function startServer(): void } } register_shutdown_function(static function () { - echo 'check ports...', \PHP_EOL; - ttyExec(\PHP_BINARY . ' ' . __DIR__ . '/bin/checkPorts.php'); + checkPorts([13456]); }); } diff --git a/src/Components/swoole-tracker/example/HttpServer/bin/start.sh b/src/Components/swoole-tracker/example/HttpServer/bin/start.sh index 3a81cfd16e..bea596533f 100644 --- a/src/Components/swoole-tracker/example/HttpServer/bin/start.sh +++ b/src/Components/swoole-tracker/example/HttpServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > /dev/null 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > /dev/null 2>&1 & diff --git a/src/Components/swoole-tracker/example/HttpServer/bin/stop.sh b/src/Components/swoole-tracker/example/HttpServer/bin/stop.sh index 3aa035b58f..b1abd27d1f 100644 --- a/src/Components/swoole-tracker/example/HttpServer/bin/stop.sh +++ b/src/Components/swoole-tracker/example/HttpServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole-tracker/example/HttpServer/config/config.php b/src/Components/swoole-tracker/example/HttpServer/config/config.php index e1fadc1a12..6a7ba464de 100644 --- a/src/Components/swoole-tracker/example/HttpServer/config/config.php +++ b/src/Components/swoole-tracker/example/HttpServer/config/config.php @@ -29,6 +29,7 @@ 'configs' => [ 'worker_num' => 1, 'task_worker_num' => 0, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/swoole-tracker/example/TCPServer/bin/start.sh b/src/Components/swoole-tracker/example/TCPServer/bin/start.sh index 3a81cfd16e..bea596533f 100644 --- a/src/Components/swoole-tracker/example/TCPServer/bin/start.sh +++ b/src/Components/swoole-tracker/example/TCPServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > /dev/null 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > /dev/null 2>&1 & diff --git a/src/Components/swoole-tracker/example/TCPServer/bin/stop.sh b/src/Components/swoole-tracker/example/TCPServer/bin/stop.sh index 3aa035b58f..b1abd27d1f 100644 --- a/src/Components/swoole-tracker/example/TCPServer/bin/stop.sh +++ b/src/Components/swoole-tracker/example/TCPServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole-tracker/example/TCPServer/config/config.php b/src/Components/swoole-tracker/example/TCPServer/config/config.php index 7385a4ee76..3e5b21e1ac 100644 --- a/src/Components/swoole-tracker/example/TCPServer/config/config.php +++ b/src/Components/swoole-tracker/example/TCPServer/config/config.php @@ -47,6 +47,8 @@ // 'package_length_offset' => 0, //第N个字节是包长度的值 // 'package_body_offset' => 4, //第几个字节开始计算长度 // 'package_max_length' => 1024 * 1024, //协议最大长度 + + 'max_wait_time' => 30, ], // EOF自动分包数据处理器 'dataParser' => \Imi\SwooleTracker\Example\TCPServer\TCPServer\DataParser\JsonObjectEOFParser::class, diff --git a/src/Components/swoole-tracker/example/UDPServer/bin/start.sh b/src/Components/swoole-tracker/example/UDPServer/bin/start.sh index 3a81cfd16e..bea596533f 100644 --- a/src/Components/swoole-tracker/example/UDPServer/bin/start.sh +++ b/src/Components/swoole-tracker/example/UDPServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > /dev/null 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > /dev/null 2>&1 & diff --git a/src/Components/swoole-tracker/example/UDPServer/bin/stop.sh b/src/Components/swoole-tracker/example/UDPServer/bin/stop.sh index 3aa035b58f..b1abd27d1f 100644 --- a/src/Components/swoole-tracker/example/UDPServer/bin/stop.sh +++ b/src/Components/swoole-tracker/example/UDPServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole-tracker/example/UDPServer/config/config.php b/src/Components/swoole-tracker/example/UDPServer/config/config.php index 8d69d2da9c..6628d530f4 100644 --- a/src/Components/swoole-tracker/example/UDPServer/config/config.php +++ b/src/Components/swoole-tracker/example/UDPServer/config/config.php @@ -31,6 +31,7 @@ 'configs' => [ // 'worker_num' => 8, // 'task_worker_num' => 16, + 'max_wait_time' => 30, ], // 数据处理器 'dataParser' => Imi\Server\DataParser\JsonObjectParser::class, diff --git a/src/Components/swoole-tracker/example/WebSocketServer/bin/start.sh b/src/Components/swoole-tracker/example/WebSocketServer/bin/start.sh index 3a81cfd16e..bea596533f 100644 --- a/src/Components/swoole-tracker/example/WebSocketServer/bin/start.sh +++ b/src/Components/swoole-tracker/example/WebSocketServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > /dev/null 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > /dev/null 2>&1 & diff --git a/src/Components/swoole-tracker/example/WebSocketServer/bin/stop.sh b/src/Components/swoole-tracker/example/WebSocketServer/bin/stop.sh index 3aa035b58f..b1abd27d1f 100644 --- a/src/Components/swoole-tracker/example/WebSocketServer/bin/stop.sh +++ b/src/Components/swoole-tracker/example/WebSocketServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole-tracker/example/WebSocketServer/config/config.php b/src/Components/swoole-tracker/example/WebSocketServer/config/config.php index d5324f8e1c..ebf8c4a720 100644 --- a/src/Components/swoole-tracker/example/WebSocketServer/config/config.php +++ b/src/Components/swoole-tracker/example/WebSocketServer/config/config.php @@ -31,6 +31,7 @@ 'port' => 13002, 'configs' => [ 'worker_num' => 1, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/swoole/src/Cron/Consts/CronTaskType.php b/src/Components/swoole/src/Cron/Consts/CronTaskType.php index 4ae02928ef..fe7bf58d0f 100644 --- a/src/Components/swoole/src/Cron/Consts/CronTaskType.php +++ b/src/Components/swoole/src/Cron/Consts/CronTaskType.php @@ -11,6 +11,8 @@ */ class CronTaskType extends \Imi\Cron\Consts\CronTaskType { + use \Imi\Util\Traits\TStaticClass; + /** * @EnumItem("随机工作进程任务") */ @@ -35,8 +37,4 @@ class CronTaskType extends \Imi\Cron\Consts\CronTaskType * @EnumItem("定时任务进程") */ public const CRON_PROCESS = 'cron_process'; - - private function __construct() - { - } } diff --git a/src/Components/swoole/src/Db/Driver/Swoole/Driver.php b/src/Components/swoole/src/Db/Driver/Swoole/Driver.php index 4596d0969d..e79870ce5b 100644 --- a/src/Components/swoole/src/Db/Driver/Swoole/Driver.php +++ b/src/Components/swoole/src/Db/Driver/Swoole/Driver.php @@ -18,6 +18,8 @@ /** * Swoole Coroutine MySQL 驱动. * + * @deprecated 3.0 + * * @Bean("SwooleMysqlDriver") */ class Driver extends MysqlBase @@ -204,13 +206,13 @@ public function commit(): bool */ public function rollBack(?int $levels = null): bool { - if (null === $levels) + if (null === $levels || ($toLevel = $this->getTransactionLevels() - $levels) <= 0) { $result = $this->instance->rollback(); } else { - $this->exec('ROLLBACK TO P' . $this->getTransactionLevels()); + $this->exec('ROLLBACK TO P' . $toLevel); $result = true; } if ($result) diff --git a/src/Components/swoole/src/Model/MemoryTableModel.php b/src/Components/swoole/src/Model/MemoryTableModel.php index e049b961f2..e2ccf01485 100644 --- a/src/Components/swoole/src/Model/MemoryTableModel.php +++ b/src/Components/swoole/src/Model/MemoryTableModel.php @@ -4,9 +4,9 @@ namespace Imi\Swoole\Model; +use Imi\Bean\Annotation\AnnotationManager; use Imi\Model\Annotation\MemoryTable; use Imi\Model\BaseModel; -use Imi\Model\ModelManager; use Imi\Swoole\Util\MemoryTableManager; /** @@ -27,7 +27,7 @@ abstract class MemoryTableModel extends BaseModel public static function find(string $key): ?self { /** @var MemoryTable|null $memoryTableAnnotation */ - $memoryTableAnnotation = ModelManager::getAnnotation(static::class, MemoryTable::class); + $memoryTableAnnotation = AnnotationManager::getClassAnnotations(static::class, MemoryTable::class)[0] ?? null; if (null === $memoryTableAnnotation) { return null; @@ -51,7 +51,7 @@ public static function find(string $key): ?self public static function select(): array { /** @var MemoryTable|null $memoryTableAnnotation */ - $memoryTableAnnotation = ModelManager::getAnnotation(static::class, MemoryTable::class); + $memoryTableAnnotation = AnnotationManager::getClassAnnotations(static::class, MemoryTable::class)[0] ?? null; if (null === $memoryTableAnnotation) { return []; @@ -67,7 +67,7 @@ public static function select(): array public function save(): void { /** @var MemoryTable|null $memoryTableAnnotation */ - $memoryTableAnnotation = ModelManager::getAnnotation($this, MemoryTable::class); + $memoryTableAnnotation = AnnotationManager::getClassAnnotations(static::__getRealClassName(), MemoryTable::class)[0] ?? null; if (null === $memoryTableAnnotation) { return; @@ -86,7 +86,7 @@ public function save(): void public function delete(): void { /** @var MemoryTable|null $memoryTableAnnotation */ - $memoryTableAnnotation = ModelManager::getAnnotation($this, MemoryTable::class); + $memoryTableAnnotation = AnnotationManager::getClassAnnotations(static::__getRealClassName(), MemoryTable::class)[0] ?? null; if (null === $memoryTableAnnotation) { return; @@ -100,7 +100,7 @@ public function delete(): void public static function deleteBatch(string ...$keys): void { /** @var MemoryTable|null $memoryTableAnnotation */ - $memoryTableAnnotation = ModelManager::getAnnotation(static::class, MemoryTable::class); + $memoryTableAnnotation = AnnotationManager::getClassAnnotations(static::class, MemoryTable::class)[0] ?? null; if (null === $memoryTableAnnotation) { return; @@ -122,7 +122,7 @@ public static function deleteBatch(string ...$keys): void public static function count(): int { /** @var MemoryTable|null $memoryTableAnnotation */ - $memoryTableAnnotation = ModelManager::getAnnotation(static::class, MemoryTable::class); + $memoryTableAnnotation = AnnotationManager::getClassAnnotations(static::class, MemoryTable::class)[0] ?? null; if (null === $memoryTableAnnotation) { return 0; diff --git a/src/Components/swoole/src/Process/BaseProcess.php b/src/Components/swoole/src/Process/BaseProcess.php index 56fce5c075..a740896c0c 100644 --- a/src/Components/swoole/src/Process/BaseProcess.php +++ b/src/Components/swoole/src/Process/BaseProcess.php @@ -20,7 +20,10 @@ public function __construct(array $data = []) { foreach ($data as $k => $v) { - $this->{$k} = $v; + if (\is_string($k) && property_exists($this, $k)) + { + $this->{$k} = $v; + } } } } diff --git a/src/Components/swoole/src/Process/ProcessManager.php b/src/Components/swoole/src/Process/ProcessManager.php index 711cb54ed3..626fb7fdc9 100644 --- a/src/Components/swoole/src/Process/ProcessManager.php +++ b/src/Components/swoole/src/Process/ProcessManager.php @@ -30,6 +30,8 @@ */ class ProcessManager { + use \Imi\Util\Traits\TStaticClass; + private static array $map = []; /** @@ -53,10 +55,6 @@ class ProcessManager private static Table $processInfoTable; - private function __construct() - { - } - public static function getMap(): array { return self::$map; diff --git a/src/Components/swoole/src/Process/ProcessPoolManager.php b/src/Components/swoole/src/Process/ProcessPoolManager.php index badb675fc1..910a506811 100644 --- a/src/Components/swoole/src/Process/ProcessPoolManager.php +++ b/src/Components/swoole/src/Process/ProcessPoolManager.php @@ -13,11 +13,9 @@ */ class ProcessPoolManager { - private static array $map = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $map = []; public static function getMap(): array { diff --git a/src/Components/swoole/src/Process/Signal.php b/src/Components/swoole/src/Process/Signal.php index 3c73a65cce..a79cdc86fa 100644 --- a/src/Components/swoole/src/Process/Signal.php +++ b/src/Components/swoole/src/Process/Signal.php @@ -10,6 +10,8 @@ class Signal { + use \Imi\Util\Traits\TStaticClass; + /** * @var Channel[][] */ @@ -24,10 +26,6 @@ class Signal private static array $waitingProcessSignals = []; - private function __construct() - { - } - public static function wait(int $signo, float $timeout = -1): bool { $channel = new Channel(1); diff --git a/src/Components/swoole/src/Server/Type.php b/src/Components/swoole/src/Server/Type.php index 9a8b40eade..7d20d77009 100644 --- a/src/Components/swoole/src/Server/Type.php +++ b/src/Components/swoole/src/Server/Type.php @@ -6,6 +6,8 @@ class Type { + use \Imi\Util\Traits\TStaticClass; + /** * 异步服务器,支持TCP、UDP、UnixSocket. */ @@ -30,8 +32,4 @@ class Type * 异步服务器,支持TCP、UDP、UnixSocket. */ public const UDP_SERVER = 'UdpServer'; - - private function __construct() - { - } } diff --git a/src/Components/swoole/src/Task/TaskManager.php b/src/Components/swoole/src/Task/TaskManager.php index ee9fe48c37..d5783a916d 100644 --- a/src/Components/swoole/src/Task/TaskManager.php +++ b/src/Components/swoole/src/Task/TaskManager.php @@ -10,11 +10,9 @@ class TaskManager { - private static array $map = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $map = []; public static function getMap(): array { diff --git a/src/Components/swoole/src/Util/AtomicManager.php b/src/Components/swoole/src/Util/AtomicManager.php index 92c7e972e6..4aa812a1e2 100644 --- a/src/Components/swoole/src/Util/AtomicManager.php +++ b/src/Components/swoole/src/Util/AtomicManager.php @@ -9,9 +9,7 @@ */ class AtomicManager { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 是否已初始化过. diff --git a/src/Components/swoole/src/Util/Coroutine.php b/src/Components/swoole/src/Util/Coroutine.php index 9e4595d0d1..e6aedc0c40 100644 --- a/src/Components/swoole/src/Util/Coroutine.php +++ b/src/Components/swoole/src/Util/Coroutine.php @@ -6,9 +6,7 @@ trait TCoroutine { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 判断当前是否在协程中运行. diff --git a/src/Components/swoole/src/Util/CoroutineChannelManager.php b/src/Components/swoole/src/Util/CoroutineChannelManager.php index c9d90c9f0f..7ba6ca1cb4 100644 --- a/src/Components/swoole/src/Util/CoroutineChannelManager.php +++ b/src/Components/swoole/src/Util/CoroutineChannelManager.php @@ -11,6 +11,8 @@ */ class CoroutineChannelManager { + use \Imi\Util\Traits\TStaticClass; + /** * \Swoole\Coroutine\Channel 数组. * @@ -23,10 +25,6 @@ class CoroutineChannelManager */ protected static bool $inited = false; - private function __construct() - { - } - public static function init(): void { foreach (Config::getAliases() as $alias) diff --git a/src/Components/swoole/src/Util/Imi.php b/src/Components/swoole/src/Util/Imi.php index 8fcf868759..475029dde4 100644 --- a/src/Components/swoole/src/Util/Imi.php +++ b/src/Components/swoole/src/Util/Imi.php @@ -13,6 +13,8 @@ class Imi { + use \Imi\Util\Traits\TStaticClass; + public const DEFAULT_PROCESS_NAMES = [ 'master' => 'imi:master:{namespace}', 'manager' => 'imi:manager:{namespace}', @@ -22,10 +24,6 @@ class Imi 'processPool' => 'imi:process-pool-{processPoolName}-{workerId}:{namespace}', ]; - private function __construct() - { - } - /** * 设置当前进程名. */ diff --git a/src/Components/swoole/src/Util/MemoryTableManager.php b/src/Components/swoole/src/Util/MemoryTableManager.php index 667a00d2c3..a5256c6b1e 100644 --- a/src/Components/swoole/src/Util/MemoryTableManager.php +++ b/src/Components/swoole/src/Util/MemoryTableManager.php @@ -15,6 +15,8 @@ */ class MemoryTableManager { + use \Imi\Util\Traits\TStaticClass; + /** * \Swoole\Table 数组. */ @@ -25,10 +27,6 @@ class MemoryTableManager */ private static bool $inited = false; - private function __construct() - { - } - public static function init(): void { self::$tables = []; diff --git a/src/Components/swoole/src/Util/Swoole.php b/src/Components/swoole/src/Util/Swoole.php index e40c3bf68a..b91dcfaba1 100644 --- a/src/Components/swoole/src/Util/Swoole.php +++ b/src/Components/swoole/src/Util/Swoole.php @@ -9,9 +9,7 @@ class Swoole { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 获取master进程pid. diff --git a/src/Components/swoole/tests/bin/checkPorts.php b/src/Components/swoole/tests/bin/checkPorts.php deleted file mode 100644 index ed6dac8661..0000000000 --- a/src/Components/swoole/tests/bin/checkPorts.php +++ /dev/null @@ -1,35 +0,0 @@ -= 10) - { - echo 'failed', \PHP_EOL; - continue 2; - } - ++$count; - sleep(1); - } - echo 'OK', \PHP_EOL; -} diff --git a/src/Components/swoole/tests/bootstrap.php b/src/Components/swoole/tests/bootstrap.php index 0b7cc12eb2..4f45e8ebd2 100644 --- a/src/Components/swoole/tests/bootstrap.php +++ b/src/Components/swoole/tests/bootstrap.php @@ -17,10 +17,10 @@ function startServer(): void function checkHttpServerStatus(): bool { $serverStarted = false; - for ($i = 0; $i < 20; ++$i) + for ($i = 0; $i < 60; ++$i) { sleep(1); - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); if ('imi' === @file_get_contents(env('HTTP_SERVER_HOST', 'http://127.0.0.1:13000/'), false, $context)) { $serverStarted = true; @@ -35,12 +35,12 @@ function checkHttpServerStatus(): bool function checkRedisSessionServerStatus(): bool { $serverStarted = false; - for ($i = 0; $i < 20; ++$i) + for ($i = 0; $i < 60; ++$i) { sleep(1); try { - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); if ('imi' === @file_get_contents('http://127.0.0.1:13001/', false, $context)) { $serverStarted = true; @@ -59,12 +59,12 @@ function checkRedisSessionServerStatus(): bool function checkWebSocketServerStatus(): bool { $serverStarted = false; - for ($i = 0; $i < 20; ++$i) + for ($i = 0; $i < 60; ++$i) { sleep(1); try { - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); @file_get_contents('http://127.0.0.1:13002/', false, $context); if (isset($http_response_header[0]) && 'HTTP/1.1 400 Bad Request' === $http_response_header[0]) { @@ -148,12 +148,12 @@ function checkUDPServerStatus(): bool function checkWebSocketServerWithRedisServerUtilStatus(): bool { $serverStarted = false; - for ($i = 0; $i < 20; ++$i) + for ($i = 0; $i < 60; ++$i) { sleep(1); try { - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); @file_get_contents('http://127.0.0.1:13008/', false, $context); if (isset($http_response_header[0]) && 'HTTP/1.1 400 Bad Request' === $http_response_header[0]) { @@ -173,12 +173,12 @@ function checkWebSocketServerWithRedisServerUtilStatus(): bool function checkWebSocketServerWithAmqpServerUtilStatus(): bool { $serverStarted = false; - for ($i = 0; $i < 20; ++$i) + for ($i = 0; $i < 60; ++$i) { sleep(1); try { - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); @file_get_contents('http://127.0.0.1:13009/', false, $context); if (isset($http_response_header[0]) && 'HTTP/1.1 400 Bad Request' === $http_response_header[0]) { @@ -198,12 +198,12 @@ function checkWebSocketServerWithAmqpServerUtilStatus(): bool function checkWebSocketServerWithAmqpRouteServerUtilStatus(): bool { $serverStarted = false; - for ($i = 0; $i < 20; ++$i) + for ($i = 0; $i < 60; ++$i) { sleep(1); try { - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); @file_get_contents('http://127.0.0.1:13010/', false, $context); if (isset($http_response_header[0]) && 'HTTP/1.1 400 Bad Request' === $http_response_header[0]) { @@ -220,11 +220,6 @@ function checkWebSocketServerWithAmqpRouteServerUtilStatus(): bool } $servers = [ - 'HttpServer' => [ - 'start' => __DIR__ . '/unit/HttpServer/bin/start.sh', - 'stop' => __DIR__ . '/unit/HttpServer/bin/stop.sh', - 'checkStatus' => 'checkHttpServerStatus', - ], 'RedisSessionServer' => [ 'start' => __DIR__ . '/unit/RedisSessionServer/bin/start.sh', 'stop' => __DIR__ . '/unit/RedisSessionServer/bin/stop.sh', @@ -266,6 +261,13 @@ function checkWebSocketServerWithAmqpRouteServerUtilStatus(): bool ]; } + // HttpServer 里有定时任务,放到最后启动,提升覆盖率测试性能 + $servers['HttpServer'] = [ + 'start' => __DIR__ . '/unit/HttpServer/bin/start.sh', + 'stop' => __DIR__ . '/unit/HttpServer/bin/stop.sh', + 'checkStatus' => 'checkHttpServerStatus', + ]; + $callbacks = []; foreach ($servers as $name => $options) { @@ -301,12 +303,11 @@ function checkWebSocketServerWithAmqpRouteServerUtilStatus(): bool }; } - batch($callbacks, 120, max(swoole_cpu_num() - 1, 1)); + batch($callbacks, 1200, max(swoole_cpu_num() - 1, 1)); register_shutdown_function(static function () { \Swoole\Runtime::enableCoroutine(false); - echo 'check ports...', \PHP_EOL; - ttyExec(\PHP_BINARY . ' ' . __DIR__ . '/bin/checkPorts.php'); + checkPorts([13000, 13001, 13002, 13003, 13004, 13005, 13006, 13007, 13008, 13009, 13010]); }); } diff --git a/src/Components/swoole/tests/unit/Component/Performance/SwooleMysqlDbTest.php b/src/Components/swoole/tests/unit/Component/Performance/SwooleMysqlDbTest.php index b758dbcad0..590a1e6734 100644 --- a/src/Components/swoole/tests/unit/Component/Performance/SwooleMysqlDbTest.php +++ b/src/Components/swoole/tests/unit/Component/Performance/SwooleMysqlDbTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Imi\Swoole\Test\Component\Tests\Performance; +namespace Imi\Swoole\Test\Component\Performance; use Imi\Test\Component\Performance\BaseDbTest; diff --git a/src/Components/swoole/tests/unit/Component/Pool/PoolTestClass.php b/src/Components/swoole/tests/unit/Component/Pool/PoolTestClass.php new file mode 100644 index 0000000000..4d135602d6 --- /dev/null +++ b/src/Components/swoole/tests/unit/Component/Pool/PoolTestClass.php @@ -0,0 +1,16 @@ +go(function () { + $object = RequestContext::getBean(PoolTestClass::class); + $this->assertInstanceOf(DbResource::class, $object->db); + }); + } +} diff --git a/src/Components/swoole/tests/unit/Component/config/config.php b/src/Components/swoole/tests/unit/Component/config/config.php index b1c5a6406b..65c5ddd297 100644 --- a/src/Components/swoole/tests/unit/Component/config/config.php +++ b/src/Components/swoole/tests/unit/Component/config/config.php @@ -14,6 +14,7 @@ 'Imi\Swoole\Test\Component\Lock', 'Imi\Swoole\Test\Component\Tests', 'Imi\Swoole\Test\Component\Async', + 'Imi\Swoole\Test\Component\Pool', ], // 'ignoreNamespace' => [ // ], diff --git a/src/Components/swoole/tests/unit/HttpServer/ApiServer/Controller/IndexController.php b/src/Components/swoole/tests/unit/HttpServer/ApiServer/Controller/IndexController.php index a8b84fce4e..fb73efbfe9 100644 --- a/src/Components/swoole/tests/unit/HttpServer/ApiServer/Controller/IndexController.php +++ b/src/Components/swoole/tests/unit/HttpServer/ApiServer/Controller/IndexController.php @@ -5,6 +5,7 @@ namespace Imi\Swoole\Test\HttpServer\ApiServer\Controller; use Imi\Aop\Annotation\Inject; +use Imi\HttpValidate\Annotation\HttpValidation; use Imi\RequestContext; use Imi\Server\Http\Annotation\ExtractData; use Imi\Server\Http\Annotation\RequestParam; @@ -22,6 +23,7 @@ use Imi\Util\Http\Consts\StatusCode; use Imi\Util\Http\MessageUtil; use Imi\Util\Stream\MemoryStream; +use Imi\Validate\Annotation\Required; use Swoole\Coroutine; /** @@ -521,4 +523,27 @@ protected function task(): void } }); } + + /** + * @Action + * + * @HttpValidation + */ + public function validateNone(): void + { + } + + /** + * @Action + * + * @HttpValidation + * + * @Required(name="$get.id") + */ + public function validate(int $id = 0): array + { + return [ + 'id' => $id, + ]; + } } diff --git a/src/Components/swoole/tests/unit/HttpServer/Tests/HttpValidationTest.php b/src/Components/swoole/tests/unit/HttpServer/Tests/HttpValidationTest.php new file mode 100644 index 0000000000..db160df531 --- /dev/null +++ b/src/Components/swoole/tests/unit/HttpServer/Tests/HttpValidationTest.php @@ -0,0 +1,30 @@ +get($this->host . 'validate'); + $data = $response->json(true); + $this->assertEquals('$get.id validate failed', $data['message'] ?? null); + + $response = $http->get($this->host . 'validate?id=1'); + $data = $response->json(true); + $this->assertEquals(['id' => 1], $data); + } + + public function testNone(): void + { + $http = new HttpRequest(); + $response = $http->get($this->host . 'validateNone'); + $data = $response->json(true); + $this->assertEquals([], $data); + } +} diff --git a/src/Components/swoole/tests/unit/HttpServer/bin/start.sh b/src/Components/swoole/tests/unit/HttpServer/bin/start.sh index f5dc586ac2..168adada0b 100755 --- a/src/Components/swoole/tests/unit/HttpServer/bin/start.sh +++ b/src/Components/swoole/tests/unit/HttpServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/swoole/tests/unit/HttpServer/bin/stop.sh b/src/Components/swoole/tests/unit/HttpServer/bin/stop.sh index 3aa035b58f..b1abd27d1f 100755 --- a/src/Components/swoole/tests/unit/HttpServer/bin/stop.sh +++ b/src/Components/swoole/tests/unit/HttpServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole/tests/unit/HttpServer/config/config.php b/src/Components/swoole/tests/unit/HttpServer/config/config.php index 6c5a8aa03c..78be34a897 100644 --- a/src/Components/swoole/tests/unit/HttpServer/config/config.php +++ b/src/Components/swoole/tests/unit/HttpServer/config/config.php @@ -81,6 +81,7 @@ 'configs' => [ 'worker_num' => 2, 'task_worker_num' => 1, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/swoole/tests/unit/RedisSessionServer/bin/start.sh b/src/Components/swoole/tests/unit/RedisSessionServer/bin/start.sh index f5dc586ac2..168adada0b 100755 --- a/src/Components/swoole/tests/unit/RedisSessionServer/bin/start.sh +++ b/src/Components/swoole/tests/unit/RedisSessionServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/swoole/tests/unit/RedisSessionServer/bin/stop.sh b/src/Components/swoole/tests/unit/RedisSessionServer/bin/stop.sh index 3aa035b58f..b1abd27d1f 100755 --- a/src/Components/swoole/tests/unit/RedisSessionServer/bin/stop.sh +++ b/src/Components/swoole/tests/unit/RedisSessionServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole/tests/unit/RedisSessionServer/config/config.php b/src/Components/swoole/tests/unit/RedisSessionServer/config/config.php index 237a0e087a..78b3ce6d70 100644 --- a/src/Components/swoole/tests/unit/RedisSessionServer/config/config.php +++ b/src/Components/swoole/tests/unit/RedisSessionServer/config/config.php @@ -68,6 +68,7 @@ 'port' => 13001, 'configs' => [ 'worker_num' => 1, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/swoole/tests/unit/TCPServer/bin/start.sh b/src/Components/swoole/tests/unit/TCPServer/bin/start.sh index f5dc586ac2..168adada0b 100755 --- a/src/Components/swoole/tests/unit/TCPServer/bin/start.sh +++ b/src/Components/swoole/tests/unit/TCPServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/swoole/tests/unit/TCPServer/bin/stop.sh b/src/Components/swoole/tests/unit/TCPServer/bin/stop.sh index 3aa035b58f..b1abd27d1f 100755 --- a/src/Components/swoole/tests/unit/TCPServer/bin/stop.sh +++ b/src/Components/swoole/tests/unit/TCPServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole/tests/unit/TCPServer/config/config.php b/src/Components/swoole/tests/unit/TCPServer/config/config.php index 68699ae08d..a9e7a74d33 100644 --- a/src/Components/swoole/tests/unit/TCPServer/config/config.php +++ b/src/Components/swoole/tests/unit/TCPServer/config/config.php @@ -72,6 +72,7 @@ // EOF自动分包 'open_eof_split' => true, // 打开EOF_SPLIT检测 'package_eof' => "\r\n", // 设置EOF + 'max_wait_time' => 30, ], 'dataParser' => \Imi\Swoole\Test\TCPServer\MainServer\Parser\JsonObjectParser::class, ], diff --git a/src/Components/swoole/tests/unit/UDPServer/bin/start.sh b/src/Components/swoole/tests/unit/UDPServer/bin/start.sh index f5dc586ac2..168adada0b 100755 --- a/src/Components/swoole/tests/unit/UDPServer/bin/start.sh +++ b/src/Components/swoole/tests/unit/UDPServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/swoole/tests/unit/UDPServer/bin/stop.sh b/src/Components/swoole/tests/unit/UDPServer/bin/stop.sh index 3aa035b58f..b1abd27d1f 100755 --- a/src/Components/swoole/tests/unit/UDPServer/bin/stop.sh +++ b/src/Components/swoole/tests/unit/UDPServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole/tests/unit/UDPServer/config/config.php b/src/Components/swoole/tests/unit/UDPServer/config/config.php index 534e1e2d76..42a091b792 100644 --- a/src/Components/swoole/tests/unit/UDPServer/config/config.php +++ b/src/Components/swoole/tests/unit/UDPServer/config/config.php @@ -68,6 +68,7 @@ 'port' => 13004, 'configs' => [ 'worker_num' => 1, + 'max_wait_time' => 30, ], // 数据处理器 'dataParser' => Imi\Server\DataParser\JsonObjectParser::class, diff --git a/src/Components/swoole/tests/unit/WebSocketServer/bin/start.sh b/src/Components/swoole/tests/unit/WebSocketServer/bin/start.sh index f5dc586ac2..168adada0b 100755 --- a/src/Components/swoole/tests/unit/WebSocketServer/bin/start.sh +++ b/src/Components/swoole/tests/unit/WebSocketServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/swoole/tests/unit/WebSocketServer/bin/stop.sh b/src/Components/swoole/tests/unit/WebSocketServer/bin/stop.sh index 3aa035b58f..b1abd27d1f 100755 --- a/src/Components/swoole/tests/unit/WebSocketServer/bin/stop.sh +++ b/src/Components/swoole/tests/unit/WebSocketServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole/tests/unit/WebSocketServer/config/config.php b/src/Components/swoole/tests/unit/WebSocketServer/config/config.php index 94fbd9679b..ebc981d1c8 100644 --- a/src/Components/swoole/tests/unit/WebSocketServer/config/config.php +++ b/src/Components/swoole/tests/unit/WebSocketServer/config/config.php @@ -74,6 +74,7 @@ 'configs' => [ 'worker_num' => 2, 'task_worker_num' => 1, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/bin/start.sh b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/bin/start.sh index f5dc586ac2..168adada0b 100755 --- a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/bin/start.sh +++ b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/bin/stop.sh b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/bin/stop.sh index 3aa035b58f..b1abd27d1f 100755 --- a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/bin/stop.sh +++ b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/config/config.php b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/config/config.php index 41e52d4eb5..109cfb9e79 100644 --- a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/config/config.php +++ b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpRouteServerUtil/config/config.php @@ -72,6 +72,7 @@ 'mode' => \SWOOLE_BASE, 'configs' => [ 'worker_num' => 2, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/bin/start.sh b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/bin/start.sh index f5dc586ac2..168adada0b 100755 --- a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/bin/start.sh +++ b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/bin/stop.sh b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/bin/stop.sh index 3aa035b58f..b1abd27d1f 100755 --- a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/bin/stop.sh +++ b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/config/config.php b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/config/config.php index 4d5952cc37..ac005603bd 100644 --- a/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/config/config.php +++ b/src/Components/swoole/tests/unit/WebSocketServerWithAmqpServerUtil/config/config.php @@ -72,6 +72,7 @@ 'mode' => \SWOOLE_BASE, 'configs' => [ 'worker_num' => 2, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/bin/start.sh b/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/bin/start.sh index f5dc586ac2..168adada0b 100755 --- a/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/bin/start.sh +++ b/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/bin/stop.sh b/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/bin/stop.sh index 3aa035b58f..b1abd27d1f 100755 --- a/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/bin/stop.sh +++ b/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" swoole/stop diff --git a/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/config/config.php b/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/config/config.php index 4ef5809107..dd85d86dfd 100644 --- a/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/config/config.php +++ b/src/Components/swoole/tests/unit/WebSocketServerWithRedisServerUtil/config/config.php @@ -75,6 +75,7 @@ 'mode' => \SWOOLE_BASE, 'configs' => [ 'worker_num' => 2, + 'max_wait_time' => 30, ], ], diff --git a/src/Components/workerman-gateway/src/Swoole/Server/Type.php b/src/Components/workerman-gateway/src/Swoole/Server/Type.php index 1d52f105e5..189192d238 100644 --- a/src/Components/workerman-gateway/src/Swoole/Server/Type.php +++ b/src/Components/workerman-gateway/src/Swoole/Server/Type.php @@ -6,6 +6,8 @@ class Type { + use \Imi\Util\Traits\TStaticClass; + /** * WebSocket 业务服务器. */ @@ -15,8 +17,4 @@ class Type * TCP 业务服务器. */ public const BUSINESS_TCP = 'SwooleGatewayTcpBusinessServer'; - - private function __construct() - { - } } diff --git a/src/Components/workerman-gateway/src/Workerman/Server/Type.php b/src/Components/workerman-gateway/src/Workerman/Server/Type.php index bf7d84ba85..e0398868e8 100644 --- a/src/Components/workerman-gateway/src/Workerman/Server/Type.php +++ b/src/Components/workerman-gateway/src/Workerman/Server/Type.php @@ -6,6 +6,8 @@ class Type { + use \Imi\Util\Traits\TStaticClass; + /** * WebSocket 业务服务器. */ @@ -25,8 +27,4 @@ class Type * 注册中心服务器. */ public const REGISTER = 'WorkermanGatewayRegisterServer'; - - private function __construct() - { - } } diff --git a/src/Components/workerman-gateway/tests/bootstrap.php b/src/Components/workerman-gateway/tests/bootstrap.php index 619caadf1a..5e5fbbce21 100644 --- a/src/Components/workerman-gateway/tests/bootstrap.php +++ b/src/Components/workerman-gateway/tests/bootstrap.php @@ -18,10 +18,10 @@ function startServer(): void function checkHttpServerStatus(): bool { $serverStarted = false; - for ($i = 0; $i < 20; ++$i) + for ($i = 0; $i < 60; ++$i) { sleep(1); - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); if ('imi' === @file_get_contents(env('HTTP_SERVER_HOST', 'http://127.0.0.1:13000/'), false, $context)) { $serverStarted = true; @@ -32,6 +32,40 @@ function checkHttpServerStatus(): bool return $serverStarted; } + // @phpstan-ignore-next-line + function checkPort13004(): bool + { + $serverStarted = false; + for ($i = 0; $i < 60; ++$i) + { + sleep(1); + if (checkPort('127.0.0.1', 13004)) + { + $serverStarted = true; + break; + } + } + + return $serverStarted; + } + + // @phpstan-ignore-next-line + function checkPort13002(): bool + { + $serverStarted = false; + for ($i = 0; $i < 60; ++$i) + { + sleep(1); + if (checkPort('127.0.0.1', 13002)) + { + $serverStarted = true; + break; + } + } + + return $serverStarted; + } + if ('\\' === \DIRECTORY_SEPARATOR) { $servers = [ @@ -51,9 +85,11 @@ function checkHttpServerStatus(): bool ], 'WorkermanRegisterServer' => [ 'start' => __DIR__ . '/unit/AppServer/bin/start-workerman.sh --name register', + 'checkStatus' => 'checkPort13004', ], 'WorkermanGatewayServer' => [ 'start' => __DIR__ . '/unit/AppServer/bin/start-workerman.sh --name gateway', + 'checkStatus' => 'checkPort13002', ], 'SwooleServer' => [ 'start' => __DIR__ . '/unit/AppServer/bin/start-swoole.sh', @@ -140,39 +176,8 @@ function runTestServer(string $name, array $options): void } } -/** - * 检查端口是否可以被绑定. - */ -function checkPort(string $host, int $port, ?int &$errno = null, ?string &$errstr = null): bool -{ - $socket = @stream_socket_client('tcp://' . $host . ':' . $port, $errno, $errstr, 3); - if (!$socket) - { - return false; - } - fclose($socket); - - return true; -} - startServer(); register_shutdown_function(static function () { - echo 'check ports...', \PHP_EOL; - foreach ([13000, 13002, 13004, 12900] as $port) - { - echo "checking port {$port}..."; - $count = 0; - while (checkPort('127.0.0.1', $port)) - { - if ($count >= 10) - { - echo 'failed', \PHP_EOL; - continue 2; - } - ++$count; - sleep(1); - } - echo 'OK', \PHP_EOL; - } + checkPorts([13000, 13002, 13004, 12900]); }); diff --git a/src/Components/workerman-gateway/tests/unit/AppServer/bin/start-swoole.sh b/src/Components/workerman-gateway/tests/unit/AppServer/bin/start-swoole.sh index 5514d23fdb..782aa50d1b 100755 --- a/src/Components/workerman-gateway/tests/unit/AppServer/bin/start-swoole.sh +++ b/src/Components/workerman-gateway/tests/unit/AppServer/bin/start-swoole.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop-swoole.sh -nohup /usr/bin/env php "$__DIR__/swoole" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/swoole" swoole/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/workerman-gateway/tests/unit/AppServer/bin/start-workerman.sh b/src/Components/workerman-gateway/tests/unit/AppServer/bin/start-workerman.sh index 325f715109..79f7dfedf0 100755 --- a/src/Components/workerman-gateway/tests/unit/AppServer/bin/start-workerman.sh +++ b/src/Components/workerman-gateway/tests/unit/AppServer/bin/start-workerman.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop-workerman.sh -nohup /usr/bin/env php "$__DIR__/workerman" workerman/start $* > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/workerman" workerman/start $* > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/workerman-gateway/tests/unit/AppServer/bin/stop-swoole.sh b/src/Components/workerman-gateway/tests/unit/AppServer/bin/stop-swoole.sh index 6ea28ef158..c3cfb572db 100755 --- a/src/Components/workerman-gateway/tests/unit/AppServer/bin/stop-swoole.sh +++ b/src/Components/workerman-gateway/tests/unit/AppServer/bin/stop-swoole.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/swoole" swoole/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/swoole" swoole/stop diff --git a/src/Components/workerman-gateway/tests/unit/AppServer/bin/stop-workerman.sh b/src/Components/workerman-gateway/tests/unit/AppServer/bin/stop-workerman.sh index 3246836436..e4232a94e7 100755 --- a/src/Components/workerman-gateway/tests/unit/AppServer/bin/stop-workerman.sh +++ b/src/Components/workerman-gateway/tests/unit/AppServer/bin/stop-workerman.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/workerman" workerman/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/workerman" workerman/stop diff --git a/src/Components/workerman-gateway/tests/unit/AppServer/config/config.php b/src/Components/workerman-gateway/tests/unit/AppServer/config/config.php index 221726c598..3ee6200547 100644 --- a/src/Components/workerman-gateway/tests/unit/AppServer/config/config.php +++ b/src/Components/workerman-gateway/tests/unit/AppServer/config/config.php @@ -72,6 +72,7 @@ 'mode' => \SWOOLE_BASE, 'configs' => [ 'worker_num' => 2, + 'max_wait_time' => 30, ], 'workermanGateway' => [ 'registerAddress' => '127.0.0.1:13004', @@ -171,6 +172,9 @@ 'ServerUtil' => Imi\WorkermanGateway\Workerman\Server\Util\GatewayServerUtil::class, ], ], + 'worker' => [ + 'stopTimeout' => 30, + ], ], 'swoole' => [ diff --git a/src/Components/workerman/src/Process/ProcessManager.php b/src/Components/workerman/src/Process/ProcessManager.php index c1c9f627bc..34c8aad4eb 100644 --- a/src/Components/workerman/src/Process/ProcessManager.php +++ b/src/Components/workerman/src/Process/ProcessManager.php @@ -26,6 +26,8 @@ */ class ProcessManager { + use \Imi\Util\Traits\TStaticClass; + private static array $map = []; /** @@ -35,10 +37,6 @@ class ProcessManager */ private static array $processes = []; - private function __construct() - { - } - public static function getMap(): array { return self::$map; diff --git a/src/Components/workerman/src/Server/Type.php b/src/Components/workerman/src/Server/Type.php index eb2fbeeae1..564899848e 100644 --- a/src/Components/workerman/src/Server/Type.php +++ b/src/Components/workerman/src/Server/Type.php @@ -6,6 +6,8 @@ class Type { + use \Imi\Util\Traits\TStaticClass; + /** * HTTP 服务器. */ @@ -30,8 +32,4 @@ class Type * Channel 服务器. */ public const CHANNEL = 'WorkermanChannelServer'; - - private function __construct() - { - } } diff --git a/src/Components/workerman/tests/bootstrap.php b/src/Components/workerman/tests/bootstrap.php index 8eb9c26527..a813316305 100644 --- a/src/Components/workerman/tests/bootstrap.php +++ b/src/Components/workerman/tests/bootstrap.php @@ -18,7 +18,7 @@ function checkHttpServerStatus(): bool for ($i = 0; $i < 20; ++$i) { sleep(1); - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); if ('imi' === @file_get_contents(env('HTTP_SERVER_HOST', 'http://127.0.0.1:13000/'), false, $context)) { $serverStarted = true; @@ -36,7 +36,7 @@ function checkChannelServerUtilServerStatus(): bool for ($i = 0; $i < 20; ++$i) { sleep(1); - $context = stream_context_create(['http' => ['timeout' => 3]]); + $context = stream_context_create(['http' => ['timeout' => 20]]); if ('imi' === @file_get_contents(env('HTTP_SERVER_HOST', 'http://127.0.0.1:13006/'), false, $context)) { $serverStarted = true; @@ -115,39 +115,8 @@ function checkChannelServerUtilServerStatus(): bool } } -/** - * 检查端口是否可以被绑定. - */ -function checkPort(string $host, int $port, ?int &$errno = null, ?string &$errstr = null): bool -{ - $socket = @stream_socket_client('tcp://' . $host . ':' . $port, $errno, $errstr, 3); - if (!$socket) - { - return false; - } - fclose($socket); - - return true; -} - startServer(); register_shutdown_function(static function () { - echo 'check ports...', \PHP_EOL; - foreach ([13000, 13002, 13003, 13004, 13005, 13006, 13007] as $port) - { - echo "checking port {$port}..."; - $count = 0; - while (checkPort('127.0.0.1', $port)) - { - if ($count >= 10) - { - echo 'failed', \PHP_EOL; - continue 2; - } - ++$count; - sleep(1); - } - echo 'OK', \PHP_EOL; - } + checkPorts([13000, 13002, 13003, 13004, 13005, 13006, 13007]); }); diff --git a/src/Components/workerman/tests/unit/AppServer/bin/start.sh b/src/Components/workerman/tests/unit/AppServer/bin/start.sh index 72308270d2..2f4cc00d8b 100755 --- a/src/Components/workerman/tests/unit/AppServer/bin/start.sh +++ b/src/Components/workerman/tests/unit/AppServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" workerman/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" workerman/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/workerman/tests/unit/AppServer/bin/stop.sh b/src/Components/workerman/tests/unit/AppServer/bin/stop.sh index 8313409359..f6cdc79eba 100755 --- a/src/Components/workerman/tests/unit/AppServer/bin/stop.sh +++ b/src/Components/workerman/tests/unit/AppServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" workerman/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" workerman/stop diff --git a/src/Components/workerman/tests/unit/AppServer/config/config.php b/src/Components/workerman/tests/unit/AppServer/config/config.php index 8d0eb0847e..2dd567d55f 100644 --- a/src/Components/workerman/tests/unit/AppServer/config/config.php +++ b/src/Components/workerman/tests/unit/AppServer/config/config.php @@ -115,6 +115,9 @@ ], 'workerman' => [ + 'worker' => [ + 'stopTimeout' => 30, + ], ], // 数据库配置 diff --git a/src/Components/workerman/tests/unit/ChannelServerUtilServer/bin/start.sh b/src/Components/workerman/tests/unit/ChannelServerUtilServer/bin/start.sh index 72308270d2..2f4cc00d8b 100755 --- a/src/Components/workerman/tests/unit/ChannelServerUtilServer/bin/start.sh +++ b/src/Components/workerman/tests/unit/ChannelServerUtilServer/bin/start.sh @@ -4,4 +4,14 @@ __DIR__=$(cd `dirname $0`; pwd) ${__DIR__}/stop.sh -nohup /usr/bin/env php "$__DIR__/imi" workerman/start > "$__DIR__/../logs/cli.log" 2>&1 & +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +nohup /usr/bin/env php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" workerman/start > "$__DIR__/../logs/cli.log" 2>&1 & diff --git a/src/Components/workerman/tests/unit/ChannelServerUtilServer/bin/stop.sh b/src/Components/workerman/tests/unit/ChannelServerUtilServer/bin/stop.sh index 8313409359..f6cdc79eba 100755 --- a/src/Components/workerman/tests/unit/ChannelServerUtilServer/bin/stop.sh +++ b/src/Components/workerman/tests/unit/ChannelServerUtilServer/bin/stop.sh @@ -2,4 +2,14 @@ __DIR__=$(cd `dirname $0`; pwd) -"$__DIR__/imi" workerman/stop +php --ri xdebug > /dev/null +if [ $? -eq 0 ]; then + paramsXdebug="" +else + php -dzend_extension=xdebug --ri xdebug > /dev/null + if [ $? -eq 0 ]; then + paramsXdebug="-dzend_extension=xdebug" + fi +fi + +php $paramsXdebug -dxdebug.mode=coverage "$__DIR__/imi" workerman/stop diff --git a/src/Components/workerman/tests/unit/ChannelServerUtilServer/config/config.php b/src/Components/workerman/tests/unit/ChannelServerUtilServer/config/config.php index 7b0a30759e..247de64812 100644 --- a/src/Components/workerman/tests/unit/ChannelServerUtilServer/config/config.php +++ b/src/Components/workerman/tests/unit/ChannelServerUtilServer/config/config.php @@ -90,6 +90,9 @@ ], 'workerman' => [ + 'worker' => [ + 'stopTimeout' => 30, + ], // 多进程通讯组件配置 'channel' => [ 'host' => env('SERVER_HOST', '127.0.0.1'), diff --git a/src/Config.php b/src/Config.php index 990f21e311..c11f41a77b 100644 --- a/src/Config.php +++ b/src/Config.php @@ -9,6 +9,8 @@ class Config { + use \Imi\Util\Traits\TStaticClass; + /** * 配置数组. * @@ -18,10 +20,6 @@ class Config private static array $dotRulesCache = []; - private function __construct() - { - } - /** * 增加配置. */ diff --git a/src/Config/DotEnv/DotEnv.php b/src/Config/DotEnv/DotEnv.php index cfb77cf690..74067045a3 100644 --- a/src/Config/DotEnv/DotEnv.php +++ b/src/Config/DotEnv/DotEnv.php @@ -10,9 +10,7 @@ class DotEnv { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; public static function load(array $paths): void { diff --git a/src/ConnectionContext.php b/src/ConnectionContext.php index 57a017daf6..af3664176d 100644 --- a/src/ConnectionContext.php +++ b/src/ConnectionContext.php @@ -11,9 +11,7 @@ class ConnectionContext { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 为当前连接创建上下文. diff --git a/src/Core/App/Enum/LoadRuntimeResult.php b/src/Core/App/Enum/LoadRuntimeResult.php index 74b5e59e8f..02074ae8de 100644 --- a/src/Core/App/Enum/LoadRuntimeResult.php +++ b/src/Core/App/Enum/LoadRuntimeResult.php @@ -6,6 +6,8 @@ class LoadRuntimeResult { + use \Imi\Util\Traits\TStaticClass; + public const NONE = 0; public const IMI_LOADED = 1; @@ -13,8 +15,4 @@ class LoadRuntimeResult public const APP_LOADED = 2; public const ALL = self::IMI_LOADED + self::APP_LOADED; - - private function __construct() - { - } } diff --git a/src/Core/Component/ComponentManager.php b/src/Core/Component/ComponentManager.php index 7eb04e33c4..11ce6bc81a 100644 --- a/src/Core/Component/ComponentManager.php +++ b/src/Core/Component/ComponentManager.php @@ -8,11 +8,9 @@ class ComponentManager { - private static array $components = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $components = []; public static function addComponent(string $name, string $namespace): void { diff --git a/src/Core/Runtime/Runtime.php b/src/Core/Runtime/Runtime.php index 32ed3a27b2..9f8686f72b 100644 --- a/src/Core/Runtime/Runtime.php +++ b/src/Core/Runtime/Runtime.php @@ -9,11 +9,9 @@ class Runtime { - private static IRuntimeModeHandler $runtimeModeHandler; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static IRuntimeModeHandler $runtimeModeHandler; public static function setRuntimeModeHandler(string $class): IRuntimeModeHandler { diff --git a/src/Cron/Consts/CronTaskType.php b/src/Cron/Consts/CronTaskType.php index 03e096cb6b..8078df22ef 100644 --- a/src/Cron/Consts/CronTaskType.php +++ b/src/Cron/Consts/CronTaskType.php @@ -12,12 +12,10 @@ */ class CronTaskType extends BaseEnum { + use \Imi\Util\Traits\TStaticClass; + /** * @EnumItem("定时任务进程") */ public const CRON_PROCESS = 'cron_process'; - - private function __construct() - { - } } diff --git a/src/Cron/Consts/UniqueLevel.php b/src/Cron/Consts/UniqueLevel.php index 8d0b2a8536..99a99e34fd 100644 --- a/src/Cron/Consts/UniqueLevel.php +++ b/src/Cron/Consts/UniqueLevel.php @@ -12,6 +12,8 @@ */ class UniqueLevel extends BaseEnum { + use \Imi\Util\Traits\TStaticClass; + /** * @EnumItem("当前实例唯一") */ @@ -21,8 +23,4 @@ class UniqueLevel extends BaseEnum * @EnumItem("所有实例唯一") */ public const ALL = 'all'; - - private function __construct() - { - } } diff --git a/src/Cron/Util/CronUtil.php b/src/Cron/Util/CronUtil.php index 41576479ae..4413d4d6f2 100644 --- a/src/Cron/Util/CronUtil.php +++ b/src/Cron/Util/CronUtil.php @@ -18,9 +18,7 @@ class CronUtil { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 上报定时任务结果. diff --git a/src/Db/Annotation/RollbackType.php b/src/Db/Annotation/RollbackType.php index 1f0d13f43a..65e1820fb3 100644 --- a/src/Db/Annotation/RollbackType.php +++ b/src/Db/Annotation/RollbackType.php @@ -6,6 +6,8 @@ class RollbackType { + use \Imi\Util\Traits\TStaticClass; + /** * 回滚所有(rollback). */ @@ -15,8 +17,4 @@ class RollbackType * 回滚部分(rollback to xxx). */ public const PART = 'part'; - - private function __construct() - { - } } diff --git a/src/Db/Annotation/Transaction.php b/src/Db/Annotation/Transaction.php index 7e53e5235b..340c0100c6 100644 --- a/src/Db/Annotation/Transaction.php +++ b/src/Db/Annotation/Transaction.php @@ -16,13 +16,13 @@ * @property string|null $dbPoolName 数据库连接池名,为null或默认都为默认连接池 * @property string $type 事务类型;默认为嵌套 * @property bool $autoCommit 自动提交事务 - * @property string $rollbackType 回滚类型;默认为回滚所有 - * @property int $rollbackLevels 回滚层数,默认为1;当 $rollbackType 为 RollbackType::PART 时有效 + * @property string $rollbackType 回滚类型;默认为回滚所有;回滚部分通常配合type=TransactionType::NESTING使用 + * @property int|null $rollbackLevels 回滚层数,默认为1;当 $rollbackType 为 RollbackType::PART 时有效。设为null则全部回滚 */ #[\Attribute(\Attribute::TARGET_METHOD)] class Transaction extends Base { - public function __construct(?array $__data = null, ?string $dbPoolName = null, string $type = TransactionType::AUTO, bool $autoCommit = true, string $rollbackType = RollbackType::ALL, int $rollbackLevels = 1) + public function __construct(?array $__data = null, ?string $dbPoolName = null, string $type = TransactionType::AUTO, bool $autoCommit = true, string $rollbackType = RollbackType::ALL, ?int $rollbackLevels = 1) { parent::__construct(...\func_get_args()); } diff --git a/src/Db/Annotation/TransactionType.php b/src/Db/Annotation/TransactionType.php index f375633440..f17d89b2d2 100644 --- a/src/Db/Annotation/TransactionType.php +++ b/src/Db/Annotation/TransactionType.php @@ -6,6 +6,8 @@ class TransactionType { + use \Imi\Util\Traits\TStaticClass; + /** * 事务嵌套. */ @@ -20,8 +22,4 @@ class TransactionType * 如果当前不在事务中则开启事务 */ public const AUTO = 'auto'; - - private function __construct() - { - } } diff --git a/src/Db/Db.php b/src/Db/Db.php index 3ac04c11ae..126aaa0cf9 100644 --- a/src/Db/Db.php +++ b/src/Db/Db.php @@ -20,15 +20,13 @@ class Db { + use \Imi\Util\Traits\TStaticClass; + /** * 连接配置. */ private static ?array $connections = null; - private function __construct() - { - } - /** * 获取新的数据库连接实例. * diff --git a/src/Db/Drivers/TPdoDriver.php b/src/Db/Drivers/TPdoDriver.php index 88c3902a5f..a849a41780 100644 --- a/src/Db/Drivers/TPdoDriver.php +++ b/src/Db/Drivers/TPdoDriver.php @@ -211,7 +211,7 @@ public function commit(): bool */ public function rollBack(?int $levels = null): bool { - if (null === $levels) + if (null === $levels || ($toLevel = $this->getTransactionLevels() - $levels) <= 0) { try { @@ -228,7 +228,7 @@ public function rollBack(?int $levels = null): bool } else { - $this->exec('ROLLBACK TO P' . $this->getTransactionLevels()); + $this->exec('ROLLBACK TO P' . $toLevel); $result = true; } if ($result) diff --git a/src/Db/Mysql/Consts/LogicalOperator.php b/src/Db/Mysql/Consts/LogicalOperator.php index e983c14fa7..d70176d9b3 100644 --- a/src/Db/Mysql/Consts/LogicalOperator.php +++ b/src/Db/Mysql/Consts/LogicalOperator.php @@ -9,6 +9,8 @@ class LogicalOperator extends BaseEnum { + use \Imi\Util\Traits\TStaticClass; + /** * @EnumItem */ @@ -38,8 +40,4 @@ class LogicalOperator extends BaseEnum * @EnumItem */ public const XOR_NOT = 'xor not'; - - private function __construct() - { - } } diff --git a/src/Db/Mysql/Drivers/Mysqli/Driver.php b/src/Db/Mysql/Drivers/Mysqli/Driver.php index 24b2234e39..cb74951a8a 100644 --- a/src/Db/Mysql/Drivers/Mysqli/Driver.php +++ b/src/Db/Mysql/Drivers/Mysqli/Driver.php @@ -192,13 +192,13 @@ public function commit(): bool */ public function rollBack(?int $levels = null): bool { - if (null === $levels) + if (null === $levels || ($toLevel = $this->getTransactionLevels() - $levels) <= 0) { $result = $this->instance->rollback(); } else { - $this->exec('ROLLBACK TO P' . $this->getTransactionLevels()); + $this->exec('ROLLBACK TO P' . $toLevel); $result = true; } if ($result) diff --git a/src/Db/Mysql/Query/MysqlQuery.php b/src/Db/Mysql/Query/MysqlQuery.php index 871df134cf..132958a5bb 100644 --- a/src/Db/Mysql/Query/MysqlQuery.php +++ b/src/Db/Mysql/Query/MysqlQuery.php @@ -88,6 +88,10 @@ public function parseKeywordText(string $string): array */ public function parseKeywordToText(array $keywords, ?string $alias = null, ?array $jsonKeywords = null): string { + if (!$keywords) + { + return ''; + } foreach ($keywords as $k => $v) { if (Text::isEmpty($v)) @@ -95,9 +99,13 @@ public function parseKeywordToText(array $keywords, ?string $alias = null, ?arra unset($keywords[$k]); } } - $isLastStar = '*' === end($keywords); + // @phpstan-ignore-next-line + if (!$keywords) + { + return ''; + } $result = '`' . implode('`.`', $keywords) . '`'; - if ($isLastStar) + if ('*' === end($keywords)) { $result = str_replace('`*`', '*', $result); } diff --git a/src/Db/Mysql/Util/SqlUtil.php b/src/Db/Mysql/Util/SqlUtil.php index b643a3be00..2b11502a5f 100644 --- a/src/Db/Mysql/Util/SqlUtil.php +++ b/src/Db/Mysql/Util/SqlUtil.php @@ -13,9 +13,7 @@ */ class SqlUtil { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 解析带冒号参数的 SQL,返回解析后的 SQL. diff --git a/src/Db/Query/Paginate.php b/src/Db/Query/Paginate.php deleted file mode 100644 index 2e9a1a1a81..0000000000 --- a/src/Db/Query/Paginate.php +++ /dev/null @@ -1,24 +0,0 @@ -page = $page; - $this->count = $count; - } -} diff --git a/src/Db/Query/QueryType.php b/src/Db/Query/QueryType.php index 6d1c5be538..ddaae040fc 100644 --- a/src/Db/Query/QueryType.php +++ b/src/Db/Query/QueryType.php @@ -6,6 +6,8 @@ class QueryType { + use \Imi\Util\Traits\TStaticClass; + /** * 读. */ @@ -15,8 +17,4 @@ class QueryType * 写. */ public const WRITE = 2; - - private function __construct() - { - } } diff --git a/src/Db/Query/Where/BaseWhere.php b/src/Db/Query/Where/BaseWhere.php index cb747fac9f..75ee9a6bf9 100644 --- a/src/Db/Query/Where/BaseWhere.php +++ b/src/Db/Query/Where/BaseWhere.php @@ -5,7 +5,6 @@ namespace Imi\Db\Query\Where; use Imi\Db\Query\Interfaces\IQuery; -use Imi\Log\Log; abstract class BaseWhere { @@ -16,8 +15,6 @@ abstract class BaseWhere public function toString(IQuery $query): string { - Log::warning(sprintf('%s object can not be used as string', static::class)); - - return ''; + throw new \RuntimeException(sprintf('%s object can not be used as string', static::class)); // @codeCoverageIgnore } } diff --git a/src/Db/Statement/StatementManager.php b/src/Db/Statement/StatementManager.php index 94935a61a9..946376bf5d 100644 --- a/src/Db/Statement/StatementManager.php +++ b/src/Db/Statement/StatementManager.php @@ -11,6 +11,8 @@ class StatementManager { + use \Imi\Util\Traits\TStaticClass; + /** * statement 缓存数据. */ @@ -26,10 +28,6 @@ class StatementManager */ private static ?int $maxCacheCount = null; - private function __construct() - { - } - /** * 设置statement缓存. */ diff --git a/src/Enum/EnumManager.php b/src/Enum/EnumManager.php index de400801c5..f5fc38a63b 100644 --- a/src/Enum/EnumManager.php +++ b/src/Enum/EnumManager.php @@ -9,11 +9,9 @@ */ class EnumManager { - private static array $map = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $map = []; public static function getMap(): array { diff --git a/src/Env.php b/src/Env.php index 5f5cee5a2f..37f0c07cd5 100644 --- a/src/Env.php +++ b/src/Env.php @@ -8,9 +8,7 @@ class Env { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * @param mixed $default diff --git a/src/Event/ClassEventManager.php b/src/Event/ClassEventManager.php index 8fbb4239a6..cc2c3f1fbd 100644 --- a/src/Event/ClassEventManager.php +++ b/src/Event/ClassEventManager.php @@ -9,11 +9,9 @@ */ class ClassEventManager { - private static array $map = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $map = []; public static function getMap(): array { diff --git a/src/Event/EventManager.php b/src/Event/EventManager.php index 8922f93f79..ba111257bf 100644 --- a/src/Event/EventManager.php +++ b/src/Event/EventManager.php @@ -9,11 +9,9 @@ */ class EventManager { - private static array $map = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $map = []; public static function getMap(): array { diff --git a/src/Facade/BaseFacade.php b/src/Facade/BaseFacade.php index 04ea0b2039..02e028be14 100644 --- a/src/Facade/BaseFacade.php +++ b/src/Facade/BaseFacade.php @@ -14,6 +14,8 @@ */ abstract class BaseFacade { + use \Imi\Util\Traits\TStaticClass; + /** * 门面缓存. * @@ -21,10 +23,6 @@ abstract class BaseFacade */ protected static array $cache = []; - private function __construct() - { - } - /** * 获取实例. * diff --git a/src/Lock/Lock.php b/src/Lock/Lock.php index 7018838775..7131635728 100644 --- a/src/Lock/Lock.php +++ b/src/Lock/Lock.php @@ -10,6 +10,8 @@ class Lock { + use \Imi\Util\Traits\TStaticClass; + /** * 配置. * @@ -26,10 +28,6 @@ class Lock private static bool $inited = false; - private function __construct() - { - } - public static function init(): void { self::$options = self::$instances = []; diff --git a/src/Log/Log.php b/src/Log/Log.php index f7209f1969..06fe8576e8 100644 --- a/src/Log/Log.php +++ b/src/Log/Log.php @@ -8,9 +8,7 @@ class Log { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; public static function get(?string $channelName = null): MonoLogger { diff --git a/src/Main/Helper.php b/src/Main/Helper.php index 37887ed7e2..dbb2aa6972 100644 --- a/src/Main/Helper.php +++ b/src/Main/Helper.php @@ -9,14 +9,12 @@ */ class Helper { + use \Imi\Util\Traits\TStaticClass; + private static array $mains = []; private static array $nameMap = []; - private function __construct() - { - } - /** * 获取主类实例对象 * diff --git a/src/Model/Annotation/DDL.php b/src/Model/Annotation/DDL.php index 8def7efb74..7f004dccf9 100644 --- a/src/Model/Annotation/DDL.php +++ b/src/Model/Annotation/DDL.php @@ -13,8 +13,8 @@ * * @Target("CLASS") * - * @property string $sql 表结构 SQL;CREATE TABLE 语句 - * @property string $decode SQL 解码函数 + * @property string $sql 表结构 SQL;CREATE TABLE 语句 + * @property callable|string|null $decode SQL 解码函数 */ #[\Attribute(\Attribute::TARGET_CLASS)] class DDL extends Base @@ -24,7 +24,12 @@ class DDL extends Base */ protected ?string $defaultFieldName = 'sql'; - public function __construct(?array $__data = null, string $sql = '', string $decode = '') + /** + * @todo $decode 类型改为:?callable + * + * @param callable|string|null $decode + */ + public function __construct(?array $__data = null, string $sql = '', $decode = null) { parent::__construct(...\func_get_args()); } @@ -34,7 +39,7 @@ public function __construct(?array $__data = null, string $sql = '', string $dec */ public function getRawSql(): string { - if ('' === $this->decode) + if (null === $this->decode || '' === $this->decode) { return $this->sql; } diff --git a/src/Model/Cli/Model/ModelGenerate.php b/src/Model/Cli/Model/ModelGenerate.php index 12674569b2..43fd550c66 100644 --- a/src/Model/Cli/Model/ModelGenerate.php +++ b/src/Model/Cli/Model/ModelGenerate.php @@ -251,7 +251,7 @@ public function generate(string $namespace, string $baseClass, ?string $database 'incrUpdate' => $tableConfig['incrUpdate'] ?? $incrUpdate, 'poolName' => $poolName, 'ddl' => $ddl, - 'ddlDecode' => $ddlDecode, + 'ddlDecode' => '' === $ddlDecode ? null : $ddlDecode, 'tableComment' => $tableComment, 'lengthCheck' => $lengthCheck, ]; diff --git a/src/Model/Cli/Model/base-template.tpl b/src/Model/Cli/Model/base-template.tpl index f8337d6390..6daaca8404 100644 --- a/src/Model/Cli/Model/base-template.tpl +++ b/src/Model/Cli/Model/base-template.tpl @@ -20,7 +20,8 @@ use as Model; * @Table(name=@ConfigValue(name="@app.models.\.name", default=""), usePrefix=, id={}, dbPoolName=@ConfigValue(name="@app.models.\.poolName", default="")) - * @DDL(sql="", decode="") + * @DDL(sql="", decode="") * diff --git a/src/Model/Enum/RedisStorageMode.php b/src/Model/Enum/RedisStorageMode.php index 46a234d53c..c7bcbbed3c 100644 --- a/src/Model/Enum/RedisStorageMode.php +++ b/src/Model/Enum/RedisStorageMode.php @@ -9,6 +9,8 @@ */ class RedisStorageMode { + use \Imi\Util\Traits\TStaticClass; + /** * 字符串模式. * @@ -29,8 +31,4 @@ class RedisStorageMode * 使用 hset/hget,将对象存到一个 key 中,member 为字段名 */ public const HASH_OBJECT = 'hash_object'; - - private function __construct() - { - } } diff --git a/src/Model/Event/ModelEvents.php b/src/Model/Event/ModelEvents.php index a024bd1ec9..493bddb763 100644 --- a/src/Model/Event/ModelEvents.php +++ b/src/Model/Event/ModelEvents.php @@ -6,6 +6,8 @@ class ModelEvents { + use \Imi\Util\Traits\TStaticClass; + /** * 初始化值前. */ @@ -111,8 +113,4 @@ class ModelEvents * 处理 save、insert、update 数据后. */ public const AFTER_PARSE_DATA = 'AfterParseData'; - - private function __construct() - { - } } diff --git a/src/Model/IdGenerator/UUIDGeneratorType.php b/src/Model/IdGenerator/UUIDGeneratorType.php index e761996575..12e8e5d5ad 100644 --- a/src/Model/IdGenerator/UUIDGeneratorType.php +++ b/src/Model/IdGenerator/UUIDGeneratorType.php @@ -11,6 +11,8 @@ */ class UUIDGeneratorType extends BaseEnum { + use \Imi\Util\Traits\TStaticClass; + public const TIME = 'time'; public const RANDOM = 'random'; @@ -18,8 +20,4 @@ class UUIDGeneratorType extends BaseEnum public const MD5 = 'md5'; public const SHA1 = 'sha1'; - - private function __construct() - { - } } diff --git a/src/Model/Model.php b/src/Model/Model.php index 4298487d89..a03b9267a9 100644 --- a/src/Model/Model.php +++ b/src/Model/Model.php @@ -109,7 +109,7 @@ public function __init(array $data = [], bool $queryRelation = true): void } else { - $realJsonDecode = ($jsonEncode ??= ($meta->getJsonDecode() ?? false)); + $realJsonDecode = ($jsonDecode ??= ($meta->getJsonDecode() ?? false)); } if ($realJsonDecode) { diff --git a/src/Model/ModelManager.php b/src/Model/ModelManager.php index 84e8c641af..822c379a66 100644 --- a/src/Model/ModelManager.php +++ b/src/Model/ModelManager.php @@ -15,8 +15,15 @@ use Imi\Model\Annotation\Table; use Imi\Model\Key\KeyRule; +/** + * @codeCoverageIgnore + * + * @deprecated 3.0 + */ class ModelManager { + use \Imi\Util\Traits\TStaticClass; + /** * 模型类注解缓存. */ @@ -67,10 +74,6 @@ class ModelManager */ private static array $extractPropertys = []; - private function __construct() - { - } - /** * 获取当前模型类的类注解. * @@ -104,8 +107,6 @@ public static function getPropertyAnnotation($object, string $propertyName, stri /** * 获取当前模型类的表名. * - * @deprecated 3.0 - * * @param string|object $object */ public static function getTable($object): string @@ -128,8 +129,6 @@ public static function getTable($object): string /** * 获取当前模型类数据库连接池名. * - * @deprecated 3.0 - * * @param string|object $object */ public static function getDbPoolName($object): string @@ -153,8 +152,6 @@ public static function getDbPoolName($object): string * 获取当前模型主键 * 如果是联合主键返回数组,否则为字符串. * - * @deprecated 3.0 - * * @param string|object $object * * @return string|string[]|null @@ -179,8 +176,6 @@ public static function getId($object) /** * 获取第一个主键. * - * @deprecated 3.0 - * * @param string|object $object */ public static function getFirstId($object): ?string @@ -193,8 +188,6 @@ public static function getFirstId($object): ?string /** * 获取当前模型字段配置. * - * @deprecated 3.0 - * * @param string|object $object * * @return \Imi\Model\Annotation\Column[] @@ -224,8 +217,6 @@ public static function getFields($object): array /** * 获取当前模型字段名数组. * - * @deprecated 3.0 - * * @param string|object $object * * @return string[] @@ -238,8 +229,6 @@ public static function getFieldNames($object): array /** * 模型是否为驼峰命名. * - * @deprecated 3.0 - * * @param string|object $object */ public static function isCamel($object): bool @@ -262,8 +251,6 @@ public static function isCamel($object): bool /** * 获取键. * - * @deprecated 3.0 - * * @param string|object $object */ public static function getKeyRule($object): KeyRule @@ -288,8 +275,6 @@ public static function getKeyRule($object): KeyRule /** * 获取Member. * - * @deprecated 3.0 - * * @param string|object $object */ public static function getMemberRule($object): KeyRule @@ -314,8 +299,6 @@ public static function getMemberRule($object): KeyRule /** * 获取当前模型类的Redis注解. * - * @deprecated 3.0 - * * @param string|object $object */ public static function getRedisEntity($object): ?RedisEntity @@ -327,8 +310,6 @@ public static function getRedisEntity($object): ?RedisEntity /** * 获取模型类的批量设置序列化注解. * - * @deprecated 3.0 - * * @param string|object $object */ public static function getSerializables($object): ?Serializables @@ -340,8 +321,6 @@ public static function getSerializables($object): ?Serializables /** * 获取模型类的提取属性注解. * - * @deprecated 3.0 - * * @param string|object $object * * @return \Imi\Model\Annotation\ExtractProperty[][] diff --git a/src/Model/ModelRelationManager.php b/src/Model/ModelRelationManager.php index 4d76c43c55..884572e7b7 100644 --- a/src/Model/ModelRelationManager.php +++ b/src/Model/ModelRelationManager.php @@ -24,15 +24,13 @@ class ModelRelationManager { + use \Imi\Util\Traits\TStaticClass; + /** * 模型关联字段名数组. */ private static array $relationFieldsNames = []; - private function __construct() - { - } - /** * 初始化模型. */ diff --git a/src/Model/RedisModel.php b/src/Model/RedisModel.php index c5923cdc4f..e5a0aa8828 100644 --- a/src/Model/RedisModel.php +++ b/src/Model/RedisModel.php @@ -5,6 +5,7 @@ namespace Imi\Model; use Imi\App; +use Imi\Bean\Annotation\AnnotationManager; use Imi\Bean\BeanFactory; use Imi\Model\Annotation\RedisEntity; use Imi\Model\Enum\RedisStorageMode; @@ -52,9 +53,12 @@ public static function __getRedisEntity($object = null): ?RedisEntity { $object = static::__getRealClassName(); } + else + { + $object = BeanFactory::getObjectClass($object); + } - // @phpstan-ignore-next-line - return ModelManager::getAnnotation($object, RedisEntity::class); + return AnnotationManager::getClassAnnotations($object, RedisEntity::class)[0] ?? null; } public function __init(array $data = []): void @@ -512,7 +516,7 @@ public static function __getKeyRule($object = null): KeyRule else { /** @var RedisEntity|null $redisEntity */ - $redisEntity = ModelManager::getAnnotation($class, RedisEntity::class); + $redisEntity = AnnotationManager::getClassAnnotations($class, RedisEntity::class)[0] ?? null; $key = $redisEntity ? $redisEntity->key : ''; preg_match_all('/{([^}]+)}/', $key, $matches); @@ -543,7 +547,7 @@ public static function __getMemberRule($object = null): KeyRule else { /** @var RedisEntity|null $redisEntity */ - $redisEntity = ModelManager::getAnnotation($class, RedisEntity::class); + $redisEntity = AnnotationManager::getClassAnnotations($class, RedisEntity::class)[0] ?? null; $key = $redisEntity ? $redisEntity->member : ''; preg_match_all('/{([^}]+)}/', $key, $matches); diff --git a/src/Model/Relation/Delete.php b/src/Model/Relation/Delete.php index 9d9268250f..dcb903a22d 100644 --- a/src/Model/Relation/Delete.php +++ b/src/Model/Relation/Delete.php @@ -19,11 +19,9 @@ class Delete { - private static array $methodCacheMap = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $methodCacheMap = []; /** * 处理删除. diff --git a/src/Model/Relation/Insert.php b/src/Model/Relation/Insert.php index e8eaa4da9b..4b7b79e73d 100644 --- a/src/Model/Relation/Insert.php +++ b/src/Model/Relation/Insert.php @@ -19,11 +19,9 @@ class Insert { - private static array $methodCacheMap = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $methodCacheMap = []; /** * 处理插入. diff --git a/src/Model/Relation/Query.php b/src/Model/Relation/Query.php index 28f5a42650..bba9acc1fb 100644 --- a/src/Model/Relation/Query.php +++ b/src/Model/Relation/Query.php @@ -23,11 +23,9 @@ class Query { - private static array $methodCacheMap = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $methodCacheMap = []; /** * 初始化. diff --git a/src/Model/Relation/Update.php b/src/Model/Relation/Update.php index 7952abcef5..9624080f01 100644 --- a/src/Model/Relation/Update.php +++ b/src/Model/Relation/Update.php @@ -21,11 +21,9 @@ class Update { - private static array $methodCacheMap = []; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static array $methodCacheMap = []; /** * 处理更新. diff --git a/src/Model/Tree/TTreeModel.php b/src/Model/Tree/TTreeModel.php index 98c3c14e59..cb41f1ebfa 100644 --- a/src/Model/Tree/TTreeModel.php +++ b/src/Model/Tree/TTreeModel.php @@ -4,8 +4,8 @@ namespace Imi\Model\Tree; +use Imi\Bean\Annotation\AnnotationManager; use Imi\Db\Query\Interfaces\IQuery; -use Imi\Model\ModelManager; use Imi\Model\Tree\Annotation\TreeModel; use Imi\Util\ArrayUtil; @@ -19,8 +19,7 @@ trait TTreeModel */ private static function __getTreeModel(): ?TreeModel { - // @phpstan-ignore-next-line - return ModelManager::getAnnotation(static::__getRealClassName(), TreeModel::class); + return AnnotationManager::getClassAnnotations(static::__getRealClassName(), TreeModel::class)[0] ?? null; } /** diff --git a/src/Pool/Annotation/PoolResource.php b/src/Pool/Annotation/PoolResource.php index ffa7627a4c..8eaca193ee 100644 --- a/src/Pool/Annotation/PoolResource.php +++ b/src/Pool/Annotation/PoolResource.php @@ -5,11 +5,14 @@ namespace Imi\Pool\Annotation; use Imi\Aop\Annotation\RequestInject; +use Imi\Bean\Annotation\Inherit; use Imi\Pool\PoolManager; /** * 连接池对象注入. * + * @Inherit + * * @Annotation * * @Target({"PROPERTY", "ANNOTATION"}) diff --git a/src/Pool/PoolManager.php b/src/Pool/PoolManager.php index 63d7c59fb8..47ec7433b6 100644 --- a/src/Pool/PoolManager.php +++ b/src/Pool/PoolManager.php @@ -14,6 +14,8 @@ class PoolManager { + use \Imi\Util\Traits\TStaticClass; + /** * \池子数组. * @@ -31,10 +33,6 @@ class PoolManager */ protected static bool $inited = false; - private function __construct() - { - } - public static function init(): void { foreach (Config::getAliases() as $alias) diff --git a/src/Pool/ResourceConfigMode.php b/src/Pool/ResourceConfigMode.php index cd7252a790..786b727c22 100644 --- a/src/Pool/ResourceConfigMode.php +++ b/src/Pool/ResourceConfigMode.php @@ -6,6 +6,8 @@ class ResourceConfigMode { + use \Imi\Util\Traits\TStaticClass; + /** * 轮询. * @@ -22,8 +24,4 @@ class ResourceConfigMode * 随机. */ public const RANDOM = 2; - - private function __construct() - { - } } diff --git a/src/Redis/Enum/RedisMode.php b/src/Redis/Enum/RedisMode.php index 310a005473..40d8e11e14 100644 --- a/src/Redis/Enum/RedisMode.php +++ b/src/Redis/Enum/RedisMode.php @@ -6,6 +6,8 @@ class RedisMode { + use \Imi\Util\Traits\TStaticClass; + /** * 单机. */ @@ -20,8 +22,4 @@ class RedisMode * 集群模式. */ public const CLUSTER = 'cluster'; - - private function __construct() - { - } } diff --git a/src/Redis/Redis.php b/src/Redis/Redis.php index 2cdc9ef071..13ea66ada7 100644 --- a/src/Redis/Redis.php +++ b/src/Redis/Redis.php @@ -252,9 +252,7 @@ */ class Redis { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * @return mixed diff --git a/src/Redis/RedisManager.php b/src/Redis/RedisManager.php index e678a029bc..13e926922a 100644 --- a/src/Redis/RedisManager.php +++ b/src/Redis/RedisManager.php @@ -13,15 +13,13 @@ class RedisManager { + use \Imi\Util\Traits\TStaticClass; + /** * 连接配置. */ private static ?array $connections = null; - private function __construct() - { - } - /** * 获取新的 Redis 连接实例. * diff --git a/src/RequestContext.php b/src/RequestContext.php index 849895f5eb..8d62b9860b 100644 --- a/src/RequestContext.php +++ b/src/RequestContext.php @@ -11,15 +11,13 @@ class RequestContext { + use \Imi\Util\Traits\TStaticClass; + /** * 上下文管理器. */ private static IContextManager $contextManager; - private function __construct() - { - } - /** * 获取上下文管理器实例. */ diff --git a/src/Server/ConnectionContext/ConnectionContextChangeEventParam.php b/src/Server/ConnectionContext/ConnectionContextChangeEventParam.php deleted file mode 100644 index 1c2579c67a..0000000000 --- a/src/Server/ConnectionContext/ConnectionContextChangeEventParam.php +++ /dev/null @@ -1,50 +0,0 @@ -clientId = $clientId; - $this->serverName = $serverName; - } - - /** - * Get 连接标识符. - * - * @return int|string - */ - public function getClientId() - { - return $this->clientId; - } - - /** - * Get 服务器名. - */ - public function getServerName(): string - { - return $this->serverName; - } -} diff --git a/src/Server/Http/Message/Proxy/RequestProxy.php b/src/Server/Http/Message/Proxy/RequestProxy.php index b823675422..58b6c66575 100644 --- a/src/Server/Http/Message/Proxy/RequestProxy.php +++ b/src/Server/Http/Message/Proxy/RequestProxy.php @@ -44,10 +44,10 @@ * @method static \Imi\Util\Http\Contract\IServerRequest withGet(array $get) * @method \Imi\Util\Http\Contract\IServerRequest setGet(array $get) * @method static \Imi\Util\Http\Contract\IServerRequest setGet(array $get) - * @method \Imi\Util\Http\Contract\IServerRequest withPost(array $post) - * @method static \Imi\Util\Http\Contract\IServerRequest withPost(array $post) - * @method \Imi\Util\Http\Contract\IServerRequest setPost(array $post) - * @method static \Imi\Util\Http\Contract\IServerRequest setPost(array $post) + * @method \Imi\Util\Http\Contract\IServerRequest withPost($post) + * @method static \Imi\Util\Http\Contract\IServerRequest withPost($post) + * @method \Imi\Util\Http\Contract\IServerRequest setPost($post) + * @method static \Imi\Util\Http\Contract\IServerRequest setPost($post) * @method \Imi\Util\Http\Contract\IServerRequest withRequest(array $request) * @method static \Imi\Util\Http\Contract\IServerRequest withRequest(array $request) * @method \Imi\Util\Http\Contract\IServerRequest setRequest(array $request) @@ -72,42 +72,42 @@ * @method static \Psr\Http\Message\ServerRequestInterface withParsedBody($data) * @method array getAttributes() * @method static array getAttributes() - * @method mixed getAttribute($name, $default = NULL) - * @method static mixed getAttribute($name, $default = NULL) - * @method \Psr\Http\Message\ServerRequestInterface withAttribute($name, $value) - * @method static \Psr\Http\Message\ServerRequestInterface withAttribute($name, $value) - * @method \Psr\Http\Message\ServerRequestInterface withoutAttribute($name) - * @method static \Psr\Http\Message\ServerRequestInterface withoutAttribute($name) + * @method mixed getAttribute(string $name, $default = NULL) + * @method static mixed getAttribute(string $name, $default = NULL) + * @method \Psr\Http\Message\ServerRequestInterface withAttribute(string $name, $value) + * @method static \Psr\Http\Message\ServerRequestInterface withAttribute(string $name, $value) + * @method \Psr\Http\Message\ServerRequestInterface withoutAttribute(string $name) + * @method static \Psr\Http\Message\ServerRequestInterface withoutAttribute(string $name) * @method string getRequestTarget() * @method static string getRequestTarget() - * @method \Psr\Http\Message\RequestInterface withRequestTarget($requestTarget) - * @method static \Psr\Http\Message\RequestInterface withRequestTarget($requestTarget) + * @method \Psr\Http\Message\RequestInterface withRequestTarget(string $requestTarget) + * @method static \Psr\Http\Message\RequestInterface withRequestTarget(string $requestTarget) * @method string getMethod() * @method static string getMethod() - * @method \Psr\Http\Message\RequestInterface withMethod($method) - * @method static \Psr\Http\Message\RequestInterface withMethod($method) + * @method \Psr\Http\Message\RequestInterface withMethod(string $method) + * @method static \Psr\Http\Message\RequestInterface withMethod(string $method) * @method \Psr\Http\Message\UriInterface getUri() * @method static \Psr\Http\Message\UriInterface getUri() - * @method \Psr\Http\Message\RequestInterface withUri(\Psr\Http\Message\UriInterface $uri, $preserveHost = false) - * @method static \Psr\Http\Message\RequestInterface withUri(\Psr\Http\Message\UriInterface $uri, $preserveHost = false) + * @method \Psr\Http\Message\RequestInterface withUri(\Psr\Http\Message\UriInterface $uri, bool $preserveHost = false) + * @method static \Psr\Http\Message\RequestInterface withUri(\Psr\Http\Message\UriInterface $uri, bool $preserveHost = false) * @method string getProtocolVersion() * @method static string getProtocolVersion() - * @method \Psr\Http\Message\MessageInterface withProtocolVersion($version) - * @method static \Psr\Http\Message\MessageInterface withProtocolVersion($version) + * @method \Psr\Http\Message\MessageInterface withProtocolVersion(string $version) + * @method static \Psr\Http\Message\MessageInterface withProtocolVersion(string $version) * @method string[][] getHeaders() * @method static string[][] getHeaders() - * @method bool hasHeader($name) - * @method static bool hasHeader($name) - * @method string[] getHeader($name) - * @method static string[] getHeader($name) - * @method string getHeaderLine($name) - * @method static string getHeaderLine($name) - * @method \Psr\Http\Message\MessageInterface withHeader($name, $value) - * @method static \Psr\Http\Message\MessageInterface withHeader($name, $value) - * @method \Psr\Http\Message\MessageInterface withAddedHeader($name, $value) - * @method static \Psr\Http\Message\MessageInterface withAddedHeader($name, $value) - * @method \Psr\Http\Message\MessageInterface withoutHeader($name) - * @method static \Psr\Http\Message\MessageInterface withoutHeader($name) + * @method bool hasHeader(string $name) + * @method static bool hasHeader(string $name) + * @method string[] getHeader(string $name) + * @method static string[] getHeader(string $name) + * @method string getHeaderLine(string $name) + * @method static string getHeaderLine(string $name) + * @method \Psr\Http\Message\MessageInterface withHeader(string $name, $value) + * @method static \Psr\Http\Message\MessageInterface withHeader(string $name, $value) + * @method \Psr\Http\Message\MessageInterface withAddedHeader(string $name, $value) + * @method static \Psr\Http\Message\MessageInterface withAddedHeader(string $name, $value) + * @method \Psr\Http\Message\MessageInterface withoutHeader(string $name) + * @method static \Psr\Http\Message\MessageInterface withoutHeader(string $name) * @method \Psr\Http\Message\StreamInterface getBody() * @method static \Psr\Http\Message\StreamInterface getBody() * @method \Psr\Http\Message\MessageInterface withBody(\Psr\Http\Message\StreamInterface $body) diff --git a/src/Server/Http/Message/Proxy/RequestProxyObject.php b/src/Server/Http/Message/Proxy/RequestProxyObject.php index d72529bed7..69399ec46d 100644 --- a/src/Server/Http/Message/Proxy/RequestProxyObject.php +++ b/src/Server/Http/Message/Proxy/RequestProxyObject.php @@ -47,10 +47,10 @@ * @method static \Imi\Util\Http\Contract\IServerRequest withGet(array $get) * @method \Imi\Util\Http\Contract\IServerRequest setGet(array $get) * @method static \Imi\Util\Http\Contract\IServerRequest setGet(array $get) - * @method \Imi\Util\Http\Contract\IServerRequest withPost(array $post) - * @method static \Imi\Util\Http\Contract\IServerRequest withPost(array $post) - * @method \Imi\Util\Http\Contract\IServerRequest setPost(array $post) - * @method static \Imi\Util\Http\Contract\IServerRequest setPost(array $post) + * @method \Imi\Util\Http\Contract\IServerRequest withPost($post) + * @method static \Imi\Util\Http\Contract\IServerRequest withPost($post) + * @method \Imi\Util\Http\Contract\IServerRequest setPost($post) + * @method static \Imi\Util\Http\Contract\IServerRequest setPost($post) * @method \Imi\Util\Http\Contract\IServerRequest withRequest(array $request) * @method static \Imi\Util\Http\Contract\IServerRequest withRequest(array $request) * @method \Imi\Util\Http\Contract\IServerRequest setRequest(array $request) @@ -75,42 +75,42 @@ * @method static \Psr\Http\Message\ServerRequestInterface withParsedBody($data) * @method array getAttributes() * @method static array getAttributes() - * @method mixed getAttribute($name, $default = NULL) - * @method static mixed getAttribute($name, $default = NULL) - * @method \Psr\Http\Message\ServerRequestInterface withAttribute($name, $value) - * @method static \Psr\Http\Message\ServerRequestInterface withAttribute($name, $value) - * @method \Psr\Http\Message\ServerRequestInterface withoutAttribute($name) - * @method static \Psr\Http\Message\ServerRequestInterface withoutAttribute($name) + * @method mixed getAttribute(string $name, $default = NULL) + * @method static mixed getAttribute(string $name, $default = NULL) + * @method \Psr\Http\Message\ServerRequestInterface withAttribute(string $name, $value) + * @method static \Psr\Http\Message\ServerRequestInterface withAttribute(string $name, $value) + * @method \Psr\Http\Message\ServerRequestInterface withoutAttribute(string $name) + * @method static \Psr\Http\Message\ServerRequestInterface withoutAttribute(string $name) * @method string getRequestTarget() * @method static string getRequestTarget() - * @method \Psr\Http\Message\RequestInterface withRequestTarget($requestTarget) - * @method static \Psr\Http\Message\RequestInterface withRequestTarget($requestTarget) + * @method \Psr\Http\Message\RequestInterface withRequestTarget(string $requestTarget) + * @method static \Psr\Http\Message\RequestInterface withRequestTarget(string $requestTarget) * @method string getMethod() * @method static string getMethod() - * @method \Psr\Http\Message\RequestInterface withMethod($method) - * @method static \Psr\Http\Message\RequestInterface withMethod($method) + * @method \Psr\Http\Message\RequestInterface withMethod(string $method) + * @method static \Psr\Http\Message\RequestInterface withMethod(string $method) * @method \Psr\Http\Message\UriInterface getUri() * @method static \Psr\Http\Message\UriInterface getUri() - * @method \Psr\Http\Message\RequestInterface withUri(\Psr\Http\Message\UriInterface $uri, $preserveHost = false) - * @method static \Psr\Http\Message\RequestInterface withUri(\Psr\Http\Message\UriInterface $uri, $preserveHost = false) + * @method \Psr\Http\Message\RequestInterface withUri(\Psr\Http\Message\UriInterface $uri, bool $preserveHost = false) + * @method static \Psr\Http\Message\RequestInterface withUri(\Psr\Http\Message\UriInterface $uri, bool $preserveHost = false) * @method string getProtocolVersion() * @method static string getProtocolVersion() - * @method \Psr\Http\Message\MessageInterface withProtocolVersion($version) - * @method static \Psr\Http\Message\MessageInterface withProtocolVersion($version) + * @method \Psr\Http\Message\MessageInterface withProtocolVersion(string $version) + * @method static \Psr\Http\Message\MessageInterface withProtocolVersion(string $version) * @method string[][] getHeaders() * @method static string[][] getHeaders() - * @method bool hasHeader($name) - * @method static bool hasHeader($name) - * @method string[] getHeader($name) - * @method static string[] getHeader($name) - * @method string getHeaderLine($name) - * @method static string getHeaderLine($name) - * @method \Psr\Http\Message\MessageInterface withHeader($name, $value) - * @method static \Psr\Http\Message\MessageInterface withHeader($name, $value) - * @method \Psr\Http\Message\MessageInterface withAddedHeader($name, $value) - * @method static \Psr\Http\Message\MessageInterface withAddedHeader($name, $value) - * @method \Psr\Http\Message\MessageInterface withoutHeader($name) - * @method static \Psr\Http\Message\MessageInterface withoutHeader($name) + * @method bool hasHeader(string $name) + * @method static bool hasHeader(string $name) + * @method string[] getHeader(string $name) + * @method static string[] getHeader(string $name) + * @method string getHeaderLine(string $name) + * @method static string getHeaderLine(string $name) + * @method \Psr\Http\Message\MessageInterface withHeader(string $name, $value) + * @method static \Psr\Http\Message\MessageInterface withHeader(string $name, $value) + * @method \Psr\Http\Message\MessageInterface withAddedHeader(string $name, $value) + * @method static \Psr\Http\Message\MessageInterface withAddedHeader(string $name, $value) + * @method \Psr\Http\Message\MessageInterface withoutHeader(string $name) + * @method static \Psr\Http\Message\MessageInterface withoutHeader(string $name) * @method \Psr\Http\Message\StreamInterface getBody() * @method static \Psr\Http\Message\StreamInterface getBody() * @method \Psr\Http\Message\MessageInterface withBody(\Psr\Http\Message\StreamInterface $body) @@ -263,7 +263,7 @@ public function setGet(array $get): \Imi\Util\Http\Contract\IServerRequest /** * {@inheritDoc} */ - public function withPost(array $post): \Imi\Util\Http\Contract\IServerRequest + public function withPost($post): \Imi\Util\Http\Contract\IServerRequest { return self::__getProxyInstance()->withPost($post); } @@ -271,7 +271,7 @@ public function withPost(array $post): \Imi\Util\Http\Contract\IServerRequest /** * {@inheritDoc} */ - public function setPost(array $post): \Imi\Util\Http\Contract\IServerRequest + public function setPost($post): \Imi\Util\Http\Contract\IServerRequest { return self::__getProxyInstance()->setPost($post); } @@ -375,7 +375,7 @@ public function getAttributes() /** * {@inheritDoc} */ - public function getAttribute($name, $default = null) + public function getAttribute(string $name, $default = null) { return self::__getProxyInstance()->getAttribute($name, $default); } @@ -383,7 +383,7 @@ public function getAttribute($name, $default = null) /** * {@inheritDoc} */ - public function withAttribute($name, $value) + public function withAttribute(string $name, $value) { return self::__getProxyInstance()->withAttribute($name, $value); } @@ -391,7 +391,7 @@ public function withAttribute($name, $value) /** * {@inheritDoc} */ - public function withoutAttribute($name) + public function withoutAttribute(string $name) { return self::__getProxyInstance()->withoutAttribute($name); } @@ -407,7 +407,7 @@ public function getRequestTarget() /** * {@inheritDoc} */ - public function withRequestTarget($requestTarget) + public function withRequestTarget(string $requestTarget) { return self::__getProxyInstance()->withRequestTarget($requestTarget); } @@ -423,7 +423,7 @@ public function getMethod() /** * {@inheritDoc} */ - public function withMethod($method) + public function withMethod(string $method) { return self::__getProxyInstance()->withMethod($method); } @@ -439,7 +439,7 @@ public function getUri() /** * {@inheritDoc} */ - public function withUri(\Psr\Http\Message\UriInterface $uri, $preserveHost = false) + public function withUri(\Psr\Http\Message\UriInterface $uri, bool $preserveHost = false) { return self::__getProxyInstance()->withUri($uri, $preserveHost); } @@ -455,7 +455,7 @@ public function getProtocolVersion() /** * {@inheritDoc} */ - public function withProtocolVersion($version) + public function withProtocolVersion(string $version) { return self::__getProxyInstance()->withProtocolVersion($version); } @@ -471,7 +471,7 @@ public function getHeaders() /** * {@inheritDoc} */ - public function hasHeader($name) + public function hasHeader(string $name) { return self::__getProxyInstance()->hasHeader($name); } @@ -479,7 +479,7 @@ public function hasHeader($name) /** * {@inheritDoc} */ - public function getHeader($name) + public function getHeader(string $name) { return self::__getProxyInstance()->getHeader($name); } @@ -487,7 +487,7 @@ public function getHeader($name) /** * {@inheritDoc} */ - public function getHeaderLine($name) + public function getHeaderLine(string $name) { return self::__getProxyInstance()->getHeaderLine($name); } @@ -495,7 +495,7 @@ public function getHeaderLine($name) /** * {@inheritDoc} */ - public function withHeader($name, $value) + public function withHeader(string $name, $value) { return self::__getProxyInstance()->withHeader($name, $value); } @@ -503,7 +503,7 @@ public function withHeader($name, $value) /** * {@inheritDoc} */ - public function withAddedHeader($name, $value) + public function withAddedHeader(string $name, $value) { return self::__getProxyInstance()->withAddedHeader($name, $value); } @@ -511,7 +511,7 @@ public function withAddedHeader($name, $value) /** * {@inheritDoc} */ - public function withoutHeader($name) + public function withoutHeader(string $name) { return self::__getProxyInstance()->withoutHeader($name); } diff --git a/src/Server/Http/Message/Proxy/ResponseProxy.php b/src/Server/Http/Message/Proxy/ResponseProxy.php index 9a8754db99..381772c7d8 100644 --- a/src/Server/Http/Message/Proxy/ResponseProxy.php +++ b/src/Server/Http/Message/Proxy/ResponseProxy.php @@ -48,28 +48,28 @@ * @method static \Imi\Util\Http\Contract\IResponse setTrailer(string $name, string $value) * @method int getStatusCode() * @method static int getStatusCode() - * @method \Psr\Http\Message\ResponseInterface withStatus($code, $reasonPhrase = '') - * @method static \Psr\Http\Message\ResponseInterface withStatus($code, $reasonPhrase = '') + * @method \Psr\Http\Message\ResponseInterface withStatus(int $code, string $reasonPhrase = '') + * @method static \Psr\Http\Message\ResponseInterface withStatus(int $code, string $reasonPhrase = '') * @method string getReasonPhrase() * @method static string getReasonPhrase() * @method string getProtocolVersion() * @method static string getProtocolVersion() - * @method \Psr\Http\Message\MessageInterface withProtocolVersion($version) - * @method static \Psr\Http\Message\MessageInterface withProtocolVersion($version) + * @method \Psr\Http\Message\MessageInterface withProtocolVersion(string $version) + * @method static \Psr\Http\Message\MessageInterface withProtocolVersion(string $version) * @method string[][] getHeaders() * @method static string[][] getHeaders() - * @method bool hasHeader($name) - * @method static bool hasHeader($name) - * @method string[] getHeader($name) - * @method static string[] getHeader($name) - * @method string getHeaderLine($name) - * @method static string getHeaderLine($name) - * @method \Psr\Http\Message\MessageInterface withHeader($name, $value) - * @method static \Psr\Http\Message\MessageInterface withHeader($name, $value) - * @method \Psr\Http\Message\MessageInterface withAddedHeader($name, $value) - * @method static \Psr\Http\Message\MessageInterface withAddedHeader($name, $value) - * @method \Psr\Http\Message\MessageInterface withoutHeader($name) - * @method static \Psr\Http\Message\MessageInterface withoutHeader($name) + * @method bool hasHeader(string $name) + * @method static bool hasHeader(string $name) + * @method string[] getHeader(string $name) + * @method static string[] getHeader(string $name) + * @method string getHeaderLine(string $name) + * @method static string getHeaderLine(string $name) + * @method \Psr\Http\Message\MessageInterface withHeader(string $name, $value) + * @method static \Psr\Http\Message\MessageInterface withHeader(string $name, $value) + * @method \Psr\Http\Message\MessageInterface withAddedHeader(string $name, $value) + * @method static \Psr\Http\Message\MessageInterface withAddedHeader(string $name, $value) + * @method \Psr\Http\Message\MessageInterface withoutHeader(string $name) + * @method static \Psr\Http\Message\MessageInterface withoutHeader(string $name) * @method \Psr\Http\Message\StreamInterface getBody() * @method static \Psr\Http\Message\StreamInterface getBody() * @method \Psr\Http\Message\MessageInterface withBody(\Psr\Http\Message\StreamInterface $body) diff --git a/src/Server/Http/Message/Proxy/ResponseProxyObject.php b/src/Server/Http/Message/Proxy/ResponseProxyObject.php index dbc423591c..636c8a4a25 100644 --- a/src/Server/Http/Message/Proxy/ResponseProxyObject.php +++ b/src/Server/Http/Message/Proxy/ResponseProxyObject.php @@ -51,28 +51,28 @@ * @method static \Imi\Util\Http\Contract\IResponse setTrailer(string $name, string $value) * @method int getStatusCode() * @method static int getStatusCode() - * @method \Psr\Http\Message\ResponseInterface withStatus($code, $reasonPhrase = '') - * @method static \Psr\Http\Message\ResponseInterface withStatus($code, $reasonPhrase = '') + * @method \Psr\Http\Message\ResponseInterface withStatus(int $code, string $reasonPhrase = '') + * @method static \Psr\Http\Message\ResponseInterface withStatus(int $code, string $reasonPhrase = '') * @method string getReasonPhrase() * @method static string getReasonPhrase() * @method string getProtocolVersion() * @method static string getProtocolVersion() - * @method \Psr\Http\Message\MessageInterface withProtocolVersion($version) - * @method static \Psr\Http\Message\MessageInterface withProtocolVersion($version) + * @method \Psr\Http\Message\MessageInterface withProtocolVersion(string $version) + * @method static \Psr\Http\Message\MessageInterface withProtocolVersion(string $version) * @method string[][] getHeaders() * @method static string[][] getHeaders() - * @method bool hasHeader($name) - * @method static bool hasHeader($name) - * @method string[] getHeader($name) - * @method static string[] getHeader($name) - * @method string getHeaderLine($name) - * @method static string getHeaderLine($name) - * @method \Psr\Http\Message\MessageInterface withHeader($name, $value) - * @method static \Psr\Http\Message\MessageInterface withHeader($name, $value) - * @method \Psr\Http\Message\MessageInterface withAddedHeader($name, $value) - * @method static \Psr\Http\Message\MessageInterface withAddedHeader($name, $value) - * @method \Psr\Http\Message\MessageInterface withoutHeader($name) - * @method static \Psr\Http\Message\MessageInterface withoutHeader($name) + * @method bool hasHeader(string $name) + * @method static bool hasHeader(string $name) + * @method string[] getHeader(string $name) + * @method static string[] getHeader(string $name) + * @method string getHeaderLine(string $name) + * @method static string getHeaderLine(string $name) + * @method \Psr\Http\Message\MessageInterface withHeader(string $name, $value) + * @method static \Psr\Http\Message\MessageInterface withHeader(string $name, $value) + * @method \Psr\Http\Message\MessageInterface withAddedHeader(string $name, $value) + * @method static \Psr\Http\Message\MessageInterface withAddedHeader(string $name, $value) + * @method \Psr\Http\Message\MessageInterface withoutHeader(string $name) + * @method static \Psr\Http\Message\MessageInterface withoutHeader(string $name) * @method \Psr\Http\Message\StreamInterface getBody() * @method static \Psr\Http\Message\StreamInterface getBody() * @method \Psr\Http\Message\MessageInterface withBody(\Psr\Http\Message\StreamInterface $body) @@ -245,7 +245,7 @@ public function getStatusCode() /** * {@inheritDoc} */ - public function withStatus($code, $reasonPhrase = '') + public function withStatus(int $code, string $reasonPhrase = '') { return self::__getProxyInstance()->withStatus($code, $reasonPhrase); } @@ -269,7 +269,7 @@ public function getProtocolVersion() /** * {@inheritDoc} */ - public function withProtocolVersion($version) + public function withProtocolVersion(string $version) { return self::__getProxyInstance()->withProtocolVersion($version); } @@ -285,7 +285,7 @@ public function getHeaders() /** * {@inheritDoc} */ - public function hasHeader($name) + public function hasHeader(string $name) { return self::__getProxyInstance()->hasHeader($name); } @@ -293,7 +293,7 @@ public function hasHeader($name) /** * {@inheritDoc} */ - public function getHeader($name) + public function getHeader(string $name) { return self::__getProxyInstance()->getHeader($name); } @@ -301,7 +301,7 @@ public function getHeader($name) /** * {@inheritDoc} */ - public function getHeaderLine($name) + public function getHeaderLine(string $name) { return self::__getProxyInstance()->getHeaderLine($name); } @@ -309,7 +309,7 @@ public function getHeaderLine($name) /** * {@inheritDoc} */ - public function withHeader($name, $value) + public function withHeader(string $name, $value) { return self::__getProxyInstance()->withHeader($name, $value); } @@ -317,7 +317,7 @@ public function withHeader($name, $value) /** * {@inheritDoc} */ - public function withAddedHeader($name, $value) + public function withAddedHeader(string $name, $value) { return self::__getProxyInstance()->withAddedHeader($name, $value); } @@ -325,7 +325,7 @@ public function withAddedHeader($name, $value) /** * {@inheritDoc} */ - public function withoutHeader($name) + public function withoutHeader(string $name) { return self::__getProxyInstance()->withoutHeader($name); } diff --git a/src/Server/Http/Route/Router.php b/src/Server/Http/Route/Router.php index 3e25d82efe..02c0b0cb2b 100644 --- a/src/Server/Http/Route/Router.php +++ b/src/Server/Http/Route/Router.php @@ -24,6 +24,8 @@ class Router protected array $dynamicRoutes = []; + protected array $pathPatternCache = []; + /** * @param string|string[] $method */ diff --git a/src/Server/Http/Route/UrlCheckResult.php b/src/Server/Http/Route/UrlCheckResult.php deleted file mode 100644 index 0d1656e3ec..0000000000 --- a/src/Server/Http/Route/UrlCheckResult.php +++ /dev/null @@ -1,30 +0,0 @@ -result = $result; - $this->params = $params; - $this->resultIgnoreCase = $resultIgnoreCase; - } -} diff --git a/src/Server/Protocol.php b/src/Server/Protocol.php index 8de19e6c39..7a358fe9b3 100644 --- a/src/Server/Protocol.php +++ b/src/Server/Protocol.php @@ -6,6 +6,8 @@ class Protocol { + use \Imi\Util\Traits\TStaticClass; + public const HTTP = 'http'; public const WEBSOCKET = 'websocket'; @@ -18,8 +20,4 @@ class Protocol self::WEBSOCKET, self::TCP, ]; - - private function __construct() - { - } } diff --git a/src/Server/Server.php b/src/Server/Server.php index 28fe15fa52..1be6283059 100644 --- a/src/Server/Server.php +++ b/src/Server/Server.php @@ -13,9 +13,7 @@ */ class Server { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 获取上下文管理器实例. diff --git a/src/Server/ServerManager.php b/src/Server/ServerManager.php index bc6ce4e9d0..7a85ca7bf0 100644 --- a/src/Server/ServerManager.php +++ b/src/Server/ServerManager.php @@ -10,6 +10,8 @@ class ServerManager { + use \Imi\Util\Traits\TStaticClass; + /** * 服务器对象数组. * @@ -17,10 +19,6 @@ class ServerManager */ private static array $servers = []; - private function __construct() - { - } - /** * 获取服务器数组. * diff --git a/src/Server/WebSocket/Enum/NonControlFrameType.php b/src/Server/WebSocket/Enum/NonControlFrameType.php index 1bd43cac75..832cb1661d 100644 --- a/src/Server/WebSocket/Enum/NonControlFrameType.php +++ b/src/Server/WebSocket/Enum/NonControlFrameType.php @@ -12,6 +12,8 @@ */ class NonControlFrameType extends BaseEnum { + use \Imi\Util\Traits\TStaticClass; + /** * @EnumItem("文本帧") */ @@ -21,8 +23,4 @@ class NonControlFrameType extends BaseEnum * @EnumItem("二进制帧") */ public const BINARY = 2; - - private function __construct() - { - } } diff --git a/src/Timer/Handler/DefaultTimer.php b/src/Timer/Handler/DefaultTimer.php index a9906a1020..b13e6dd016 100644 --- a/src/Timer/Handler/DefaultTimer.php +++ b/src/Timer/Handler/DefaultTimer.php @@ -10,6 +10,8 @@ /** * 默认定时器,无定时功能,立即执行. * + * @codeCoverageIgnore + * * @Bean("DefaultTimer") */ class DefaultTimer implements ITimer @@ -19,9 +21,7 @@ class DefaultTimer implements ITimer */ public function tick(int $ms, callable $callback): int { - $callback(); - - return 0; + throw new \RuntimeException('Unsupport tick timer'); } /** @@ -29,9 +29,7 @@ public function tick(int $ms, callable $callback): int */ public function after(int $ms, callable $callback): int { - $callback(); - - return 0; + throw new \RuntimeException('Unsupport after timer'); } /** @@ -39,6 +37,7 @@ public function after(int $ms, callable $callback): int */ public function del(int $id): void { + throw new \RuntimeException('Unsupport del timer'); } /** diff --git a/src/Timer/Timer.php b/src/Timer/Timer.php index d7e8850523..d13af9c3b5 100644 --- a/src/Timer/Timer.php +++ b/src/Timer/Timer.php @@ -9,15 +9,13 @@ class Timer { + use \Imi\Util\Traits\TStaticClass; + /** * 定时器. */ private static ITimer $timer; - private function __construct() - { - } - /** * 获取定时器实例. */ diff --git a/src/Util/ArrayData.php b/src/Util/ArrayData.php index 2aef287b39..e7e0acbc69 100644 --- a/src/Util/ArrayData.php +++ b/src/Util/ArrayData.php @@ -96,54 +96,53 @@ public function &get($name = null, $default = false) if (\is_string($name)) { $name = explode('.', $name); + // TODO: 3.0 去除判断 + // @phpstan-ignore-next-line + if (false === $name) + { + // @codeCoverageIgnoreStart + return $default; + // @codeCoverageIgnoreEnd + } } elseif (!\is_array($name)) { return $default; } $result = &$this->__data; - if ($name) + foreach ($name as $value) { - foreach ($name as $value) + if (\is_array($result)) { - if (\is_array($result)) + // 数组 + if (isset($result[$value])) { - // 数组 - if (isset($result[$value])) - { - $result = &$result[$value]; - } - else - { - return $default; - } + $result = &$result[$value]; } - elseif (\is_object($result)) + else { - // 对象 - if (property_exists($result, $value)) - { - $result = &$result->{$value}; - } - else - { - return $default; - } + return $default; + } + } + elseif (\is_object($result)) + { + // 对象 + if (property_exists($result, $value)) + { + $result = &$result->{$value}; } else { return $default; } } + else + { + return $default; + } } - if (isset($value)) - { - return $result; - } - else - { - return $default; - } + + return $result; } /** @@ -165,7 +164,7 @@ public function remove($name): bool { $val = explode('.', $val); } - elseif (!\is_array($val)) + if (!\is_array($val)) { return false; } diff --git a/src/Util/ArrayList.php b/src/Util/ArrayList.php index 51ae9139c9..927cfc7090 100644 --- a/src/Util/ArrayList.php +++ b/src/Util/ArrayList.php @@ -88,11 +88,7 @@ public function offsetSet($offset, $value): void */ public function offsetUnset($offset): void { - $list = &$this->list; - if (isset($list[$offset])) - { - unset($list[$offset]); - } + unset($this->list[$offset]); } /** diff --git a/src/Util/ArrayUtil.php b/src/Util/ArrayUtil.php index ab261e2554..180ccdf76c 100644 --- a/src/Util/ArrayUtil.php +++ b/src/Util/ArrayUtil.php @@ -9,9 +9,7 @@ */ class ArrayUtil { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 从数组中移除一个或多个元素,重新组织为连续的键. @@ -125,10 +123,6 @@ public static function random(array $array, int $number = 1, bool $keepKey = tru $keys = array_rand($array, $number); foreach ((array) $keys as $key) { - if (!isset($array[$key])) - { - break; - } if ($keepKey) { $result[$key] = $array[$key]; diff --git a/src/Util/Bit.php b/src/Util/Bit.php index 4579768769..375189ec63 100644 --- a/src/Util/Bit.php +++ b/src/Util/Bit.php @@ -9,9 +9,7 @@ */ class Bit { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 判断是否包含值 diff --git a/src/Util/ClassObject.php b/src/Util/ClassObject.php index 31ae346502..b3f25bb488 100644 --- a/src/Util/ClassObject.php +++ b/src/Util/ClassObject.php @@ -11,9 +11,7 @@ */ class ClassObject { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 是否是匿名类对象 @@ -138,7 +136,7 @@ public static function convertKVToArray(array $params, array $args): array else { $declaringClass = $param->getDeclaringClass(); - throw new \InvalidArgumentException(sprintf('%s::__construct() %s not found', $declaringClass ? $declaringClass->getName() : '', $name)); + throw new \InvalidArgumentException(sprintf('Argument %s of %s::__construct() does not found', $name, $declaringClass ? $declaringClass->getName() : '')); } } diff --git a/src/Util/Composer.php b/src/Util/Composer.php index cfad61b895..596f8af397 100644 --- a/src/Util/Composer.php +++ b/src/Util/Composer.php @@ -12,14 +12,12 @@ */ class Composer { + use \Imi\Util\Traits\TStaticClass; + private static ?array $classLoaders = null; private static ?array $classLoadersWithVendorDir = null; - private function __construct() - { - } - /** * 获取 Composer ClassLoader 对象 * diff --git a/src/Util/DateTime.php b/src/Util/DateTime.php index 8741feea08..03dbec8cb8 100644 --- a/src/Util/DateTime.php +++ b/src/Util/DateTime.php @@ -9,9 +9,7 @@ */ class DateTime { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 将一个 \DateInterval,与当前时间进行计算,获取秒数. @@ -104,14 +102,14 @@ public static function getNextWeek(?int $weekNo = null, ?string $format = null, * * @return string|int */ - public static function getLastWeek(?int $weekNo = null, ?string $format = null, ?int $timestamp = null) + public static function getPrevWeek(?int $weekNo = null, ?string $format = null, ?int $timestamp = null) { if (null === $timestamp) { $timestamp = time(); } $currentWeek = date('N', $timestamp); - $timestamp -= ((7 - $currentWeek + ($weekNo ?? $currentWeek)) * 86400); + $timestamp -= (7 + $currentWeek - ($weekNo ?? $currentWeek)) * 86400; if (null === $format) { return $timestamp; @@ -120,6 +118,24 @@ public static function getLastWeek(?int $weekNo = null, ?string $format = null, return date($format, $timestamp); } + /** + * 获取上周的时间. + * + * 可传入 $weekNo 指定周几,周一到周日为1-7,不传则取时间戳对应周几 + * 可传入 $format 格式化,不传则返回时间戳 + * 可传入 $timestamp 指定时间戳,不传则取当前时间 + * + * @deprecated 3.0 错误的方法命名,请使用 getPrevWeek() + * + * @codeCoverageIgnore + * + * @return string|int + */ + public static function getLastWeek(?int $weekNo = null, ?string $format = null, ?int $timestamp = null) + { + return static::getPrevWeek($weekNo, $format, $timestamp); + } + /** * 获取一个月中的第几周. * @@ -147,13 +163,9 @@ public static function getWeekOfMonth(?int $timestamp = null): int $weeks = 1; $days -= (8 - $week); } - $weeks += (int) ($days / 7); - if ($days % 7 > 0) - { - ++$weeks; - } + $weeks += ceil($days / 7); - return $weeks; + return (int) $weeks; } /** @@ -175,8 +187,8 @@ public static function getMonthWeekCount(int $year, int $month): int $weeks = 1; $days -= (8 - $week); } - $weeks += (int) ($days / 7) + 1; + $weeks += ceil($days / 7); - return $weeks; + return (int) $weeks; } } diff --git a/src/Util/DelayBeanCallable.php b/src/Util/DelayBeanCallable.php index 2e282bf23b..2fdf2ad583 100644 --- a/src/Util/DelayBeanCallable.php +++ b/src/Util/DelayBeanCallable.php @@ -18,6 +18,8 @@ class DelayBeanCallable private ?bool $returnsReference = null; + private ?object $instance = null; + public function __construct(string $beanName, string $methodName, array $constructArgs = []) { $this->beanName = $beanName; @@ -37,7 +39,7 @@ public function getMethodName(): string public function getInstance(): object { - return App::getBean($this->beanName, ...$this->constructArgs); + return $this->instance ??= App::getBean($this->beanName, ...$this->constructArgs); } public function returnsReference(): bool @@ -50,7 +52,7 @@ public function returnsReference(): bool * * @return mixed */ - public function __invoke(...$args) + public function &__invoke(...$args) { if ($this->returnsReference()) { @@ -58,7 +60,23 @@ public function __invoke(...$args) } else { - return $this->getInstance()->{$this->methodName}(...$args); + $result = $this->getInstance()->{$this->methodName}(...$args); + + return $result; } } + + public function __serialize(): array + { + return [ + 'beanName' => $this->beanName, + 'methodName' => $this->methodName, + 'constructArgs' => $this->constructArgs, + ]; + } + + public function __unserialize(array $data): void + { + ['beanName' => $this->beanName, 'methodName' => $this->methodName, 'constructArgs' => $this->constructArgs] = $data; + } } diff --git a/src/Util/DelayClassCallable.php b/src/Util/DelayClassCallable.php index 0dafdd6db8..c845cf621d 100644 --- a/src/Util/DelayClassCallable.php +++ b/src/Util/DelayClassCallable.php @@ -17,6 +17,8 @@ class DelayClassCallable private ?bool $returnsReference = null; + private ?object $instance = null; + public function __construct(string $className, string $methodName, array $constructArgs = []) { $this->className = $className; @@ -36,7 +38,7 @@ public function getMethodName(): string public function getInstance(): object { - return App::getSingleton($this->className, ...$this->constructArgs); + return $this->instance ??= App::getSingleton($this->className, ...$this->constructArgs); } public function returnsReference(): bool @@ -62,4 +64,18 @@ public function &__invoke(...$args) return $result; } } + + public function __serialize(): array + { + return [ + 'className' => $this->className, + 'methodName' => $this->methodName, + 'constructArgs' => $this->constructArgs, + ]; + } + + public function __unserialize(array $data): void + { + ['className' => $this->className, 'methodName' => $this->methodName, 'constructArgs' => $this->constructArgs] = $data; + } } diff --git a/src/Util/DelayServerBeanCallable.php b/src/Util/DelayServerBeanCallable.php index ac7c6318e4..2523f9fd11 100644 --- a/src/Util/DelayServerBeanCallable.php +++ b/src/Util/DelayServerBeanCallable.php @@ -23,6 +23,8 @@ class DelayServerBeanCallable private ?bool $returnsReference = null; + private ?object $instance = null; + /** * @param string|IServer $server */ @@ -60,7 +62,7 @@ public function getServer(): IServer public function getInstance(): object { - return $this->getServer()->getBean($this->beanName, ...$this->constructArgs); + return $this->instance ??= $this->getServer()->getBean($this->beanName, ...$this->constructArgs); } public function returnsReference(): bool @@ -73,7 +75,7 @@ public function returnsReference(): bool * * @return mixed */ - public function __invoke(...$args) + public function &__invoke(...$args) { if ($this->returnsReference()) { @@ -81,7 +83,9 @@ public function __invoke(...$args) } else { - return $this->getInstance()->{$this->methodName}(...$args); + $result = $this->getInstance()->{$this->methodName}(...$args); + + return $result; } } @@ -92,12 +96,11 @@ public function __serialize(): array 'beanName' => $this->beanName, 'methodName' => $this->methodName, 'constructArgs' => $this->constructArgs, - 'returnsReference' => $this->returnsReference, ]; } public function __unserialize(array $data): void { - ['server' => $this->server, 'beanName' => $this->beanName, 'methodName' => $this->methodName, 'constructArgs' => $this->constructArgs, 'returnsReference' => $this->returnsReference] = $data; + ['server' => $this->server, 'beanName' => $this->beanName, 'methodName' => $this->methodName, 'constructArgs' => $this->constructArgs] = $data; } } diff --git a/src/Util/Digital.php b/src/Util/Digital.php index 5e14e1cd01..e2905559bf 100644 --- a/src/Util/Digital.php +++ b/src/Util/Digital.php @@ -9,9 +9,7 @@ */ class Digital { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 科学计数转小数形式的. diff --git a/src/Util/DocBlock.php b/src/Util/DocBlock.php index 7aa373bc2d..e454bf7a21 100644 --- a/src/Util/DocBlock.php +++ b/src/Util/DocBlock.php @@ -11,11 +11,9 @@ class DocBlock { - private static ?DocBlockFactory $factory = null; + use \Imi\Util\Traits\TStaticClass; - private function __construct() - { - } + private static ?DocBlockFactory $factory = null; public static function getFactory(): DocBlockFactory { diff --git a/src/Util/File.php b/src/Util/File.php index a5c7bbe25a..9b8ad4335f 100644 --- a/src/Util/File.php +++ b/src/Util/File.php @@ -15,9 +15,7 @@ */ class File { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 枚举文件. @@ -71,7 +69,7 @@ public static function enumPHPFile(string $dirPath, string $pattern = '/^.+\.php /** * 枚举文件,支持自定义中断进入下一级目录. * - * @return \Generator|iterable|false + * @return \Generator|iterable */ public static function enumFile(string $dirPath, ?string $pattern = null, array $extensionNames = []) { @@ -84,19 +82,31 @@ public static function enumFile(string $dirPath, ?string $pattern = null, array { $channel = new \Swoole\Coroutine\Channel(16); Coroutine::create(static function () use ($channel, $dirPath, $pattern, $extensionNames) { - static::enumFileSwoole($channel, $dirPath, $pattern, $extensionNames); + if (false === static::enumFileSwoole($channel, $dirPath, $pattern, $extensionNames)) + { + $channel->push(false); + } $channel->close(); }); while (false !== ($result = $channel->pop())) { yield $result; } + if (false === $result) + { + return false; + } } else { # endif - yield from self::enumFileSync($dirPath, $pattern, $extensionNames); + $result = self::enumFileSync($dirPath, $pattern, $extensionNames); + yield from $result; + if (false === $result->getReturn()) + { + return false; + } # if \extension_loaded('swoole') } @@ -106,7 +116,7 @@ public static function enumFile(string $dirPath, ?string $pattern = null, array /** * 同步枚举文件,支持自定义中断进入下一级目录. * - * @return \Generator|iterable|false + * @return \Generator|iterable */ public static function enumFileSync(string $dirPath, ?string $pattern = null, array $extensionNames = []) { @@ -242,7 +252,7 @@ public static function createDir(string $dir, int $mode = 0775): bool } else { - return false; + return false; // @codeCoverageIgnore } } @@ -276,7 +286,7 @@ public static function createFile(string $file, string $content = '', int $mode return true; } - return false; + return false; // @codeCoverageIgnore } /** @@ -299,6 +309,11 @@ public static function isEmptyDir(string $dir): bool } } } + catch (\ErrorException $_) + { + // 兼容警告转异常 + return true; + } finally { if (isset($handler) && $handler) @@ -349,7 +364,7 @@ public static function putContents(string $fileName, string $data, int $flags = $dir = \dirname($fileName); if (!static::createDir($dir)) { - throw new \RuntimeException(sprintf('Create dir %s failed', $dir)); + throw new \RuntimeException(sprintf('Create dir %s failed', $dir)); // @codeCoverageIgnore } return file_put_contents($fileName, $data, $flags, $context); diff --git a/src/Util/FilterableList.php b/src/Util/FilterableList.php index 229b73ceb2..12595da098 100644 --- a/src/Util/FilterableList.php +++ b/src/Util/FilterableList.php @@ -74,13 +74,14 @@ public function &offsetGet($offset) */ public function offsetSet($offset, $value): void { + $values = $this->parseList([$value]); if (null === $offset) { - $this->list[] = $value; + $this->list[] = $values[0]; } else { - $this->list[$offset] = $value; + $this->list[$offset] = $values[0]; } } @@ -89,11 +90,7 @@ public function offsetSet($offset, $value): void */ public function offsetUnset($offset): void { - $list = $this->list; - if (isset($list[$offset])) - { - unset($list[$offset]); - } + unset($this->list[$offset]); } /** @@ -155,7 +152,7 @@ public function jsonSerialize() */ public function remove(...$value): void { - $this->list = ArrayUtil::remove($this->list, ...$value); + $this->list = ArrayUtil::removeKeepKey($this->list, ...$value); } /** @@ -173,6 +170,7 @@ public function clear(): void */ public function append(...$value): void { + $value = $this->parseList($value); foreach ($value as $row) { $this[] = $row; diff --git a/src/Util/Http/Consts/MediaType.php b/src/Util/Http/Consts/MediaType.php index 4a46c81595..5d051d6d67 100644 --- a/src/Util/Http/Consts/MediaType.php +++ b/src/Util/Http/Consts/MediaType.php @@ -9,6 +9,8 @@ */ class MediaType { + use \Imi\Util\Traits\TStaticClass; + public const ALL = '*/*'; public const APPLICATION_ATOM_XML = 'application/atom+xml'; @@ -196,10 +198,6 @@ class MediaType 'png' => 'image/png', ]; - private function __construct() - { - } - /** * 获取扩展名对应的 Content-Type. */ diff --git a/src/Util/Http/Consts/RequestHeader.php b/src/Util/Http/Consts/RequestHeader.php index 10fe6e65a8..8a0d371873 100644 --- a/src/Util/Http/Consts/RequestHeader.php +++ b/src/Util/Http/Consts/RequestHeader.php @@ -9,6 +9,8 @@ */ class RequestHeader { + use \Imi\Util\Traits\TStaticClass; + public const ACCEPT = 'Accept'; public const ACCEPT_CHARSET = 'Accept-Charset'; public const ACCEPT_ENCODING = 'Accept-Encoding'; @@ -42,8 +44,4 @@ class RequestHeader public const VIA = 'Via'; public const WARNING = 'Warning'; public const TRAILER = 'trailer'; - - private function __construct() - { - } } diff --git a/src/Util/Http/Consts/RequestMethod.php b/src/Util/Http/Consts/RequestMethod.php index 3ec6dcc1e4..e3ee623c11 100644 --- a/src/Util/Http/Consts/RequestMethod.php +++ b/src/Util/Http/Consts/RequestMethod.php @@ -9,6 +9,8 @@ */ class RequestMethod { + use \Imi\Util\Traits\TStaticClass; + public const GET = 'GET'; public const POST = 'POST'; @@ -24,8 +26,4 @@ class RequestMethod public const OPTIONS = 'OPTIONS'; public const TRACE = 'TRACE'; - - private function __construct() - { - } } diff --git a/src/Util/Http/Consts/ResponseHeader.php b/src/Util/Http/Consts/ResponseHeader.php index cf3648e496..9dd1361da4 100644 --- a/src/Util/Http/Consts/ResponseHeader.php +++ b/src/Util/Http/Consts/ResponseHeader.php @@ -9,6 +9,8 @@ */ class ResponseHeader { + use \Imi\Util\Traits\TStaticClass; + public const ACCESS_CONTROL_ALLOW_ORIGIN = 'Access-Control-Allow-Origin'; public const ACCEPT_PATCH = 'Accept-Patch'; public const ACCEPT_RANGES = 'Accept-Ranges'; @@ -46,8 +48,4 @@ class ResponseHeader public const VIA = 'Via'; public const WARNING = 'Warning'; public const WWW_AUTHENTICATE = 'WWW-Authenticate'; - - private function __construct() - { - } } diff --git a/src/Util/Http/Consts/StatusCode.php b/src/Util/Http/Consts/StatusCode.php index 2f3c837e10..7973dd1645 100644 --- a/src/Util/Http/Consts/StatusCode.php +++ b/src/Util/Http/Consts/StatusCode.php @@ -6,6 +6,8 @@ class StatusCode { + use \Imi\Util\Traits\TStaticClass; + public const CONTINUE = 100; public const SWITCHING_PROTOCOLS = 101; public const PROCESSING = 102; @@ -132,10 +134,6 @@ class StatusCode self::NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required', ]; - private function __construct() - { - } - /** * 根据状态码获取原因短语. */ diff --git a/src/Util/Http/Contract/IServerRequest.php b/src/Util/Http/Contract/IServerRequest.php index d3e0b1448d..fea3283bcb 100644 --- a/src/Util/Http/Contract/IServerRequest.php +++ b/src/Util/Http/Contract/IServerRequest.php @@ -196,16 +196,20 @@ public function setGet(array $get): self; /** * 设置 POST 数据. * + * @param mixed $post + * * @return static */ - public function withPost(array $post): self; + public function withPost($post): self; /** * 设置 POST 数据. * + * @param mixed $post + * * @return static */ - public function setPost(array $post): self; + public function setPost($post): self; /** * 设置 Request 数据. diff --git a/src/Util/Http/Request.php b/src/Util/Http/Request.php index e41d7fdde3..58544c1a9f 100644 --- a/src/Util/Http/Request.php +++ b/src/Util/Http/Request.php @@ -31,12 +31,29 @@ class Request extends AbstractMessage implements IRequest */ protected bool $methodInited = false; + /** + * 请求目标. + */ + protected ?string $requestTarget = null; + /** * {@inheritDoc} */ public function getRequestTarget() { - return (string) $this->uri; + if (null === $this->requestTarget) + { + $uri = $this->getUri(); + $requestTarget = $uri->getPath(); + if ('' !== ($query = $uri->getQuery())) + { + $requestTarget .= '?' . $query; + } + + return $requestTarget; + } + + return $this->requestTarget; } /** @@ -45,7 +62,7 @@ public function getRequestTarget() public function withRequestTarget($requestTarget) { $self = clone $this; - $self->withUri(new Uri($requestTarget)); + $self->requestTarget = $requestTarget; return $self; } @@ -55,7 +72,7 @@ public function withRequestTarget($requestTarget) */ public function setRequestTarget($requestTarget): self { - $this->setUri(new Uri($requestTarget)); + $this->requestTarget = $requestTarget; return $this; } diff --git a/src/Util/Http/ServerRequest.php b/src/Util/Http/ServerRequest.php index 1d92aa1871..4523c8476f 100644 --- a/src/Util/Http/ServerRequest.php +++ b/src/Util/Http/ServerRequest.php @@ -9,6 +9,7 @@ use Imi\Util\Http\Consts\MediaType; use Imi\Util\Http\Consts\RequestHeader; use Imi\Util\Http\Contract\IServerRequest; +use Imi\Util\ObjectArrayHelper; class ServerRequest extends \Imi\Util\Http\Request implements IServerRequest { @@ -29,8 +30,10 @@ class ServerRequest extends \Imi\Util\Http\Request implements IServerRequest /** * post数据. + * + * @var mixed */ - protected array $post = []; + protected $post = []; /** * 包含 GET/POST/Cookie 数据. @@ -327,7 +330,7 @@ public function getParsedBody() MediaType::APPLICATION_XML, ])) { - $parsedBody = new \DOMDocument(); + $this->post = $parsedBody = new \DOMDocument(); $parsedBody->loadXML($this->body->getContents()); } // 其它 @@ -471,7 +474,7 @@ public function post(?string $name = null, $default = null) } else { - return $this->post[$name] ?? $default; + return ObjectArrayHelper::get($this->post, $name, $default); } } @@ -500,7 +503,7 @@ public function hasPost(string $name): bool $this->requestParamsInited = true; } - return isset($this->post[$name]); + return ObjectArrayHelper::exists($this->post, $name); } /** @@ -516,7 +519,7 @@ public function request(?string $name = null, $default = null) $request = &$this->request; if (null === $request) { - $request = array_merge($this->get, $this->post, $this->cookies); + $request = array_merge($this->get, \is_array($this->post) ? $this->post : ObjectArrayHelper::toArray($this->post), $this->cookies); } if (null === $name) { @@ -538,13 +541,8 @@ public function hasRequest(string $name): bool $this->initRequestParams(); $this->requestParamsInited = true; } - $request = &$this->request; - if (null === $request) - { - $request = array_merge($this->get, $this->post, $this->cookies); - } - return isset($request[$name]); + return isset($this->request()[$name]); } /** @@ -581,7 +579,7 @@ public function setGet(array $get): self /** * {@inheritDoc} */ - public function withPost(array $post): self + public function withPost($post): self { $self = clone $this; if (!$self->requestParamsInited) @@ -597,7 +595,7 @@ public function withPost(array $post): self /** * {@inheritDoc} */ - public function setPost(array $post): self + public function setPost($post): self { if (!$this->requestParamsInited) { diff --git a/src/Util/Imi.php b/src/Util/Imi.php index c87218c7b9..a80d3a5ebd 100644 --- a/src/Util/Imi.php +++ b/src/Util/Imi.php @@ -22,9 +22,7 @@ */ class Imi { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 处理规则,暂只支持通配符*. @@ -103,7 +101,7 @@ public static function checkCompareRule(string $rule, callable $valueCallback): { if (isset($rule[0]) && '!' === $rule[0]) { - // 不应该存在参数支持 + // 必须不包含参数 return null === $valueCallback(substr($rule, 1)); } elseif (preg_match('/([^!<=]+)(!=|<>|=)(.+)/', $rule, $matches) > 0) @@ -117,7 +115,7 @@ public static function checkCompareRule(string $rule, callable $valueCallback): case '=': return $value == $matches[3]; default: - return false; + return false; // @codeCoverageIgnore } } else @@ -551,6 +549,8 @@ public static function incrUpdateRuntime(array $files): void /** * 检查系统是否支持端口重用. + * + * @codeCoverageIgnore */ public static function checkReusePort(): bool { @@ -600,7 +600,7 @@ public static function eval(string $code, ?string $fileName = null, bool $delete if (false === file_put_contents($fileName, '{$nameItem} ??= new \stdClass(); - $data = &$data->{$nameItem}; + if (\is_array($data)) + { + $data[$nameItem] ??= []; + $data = &$data[$nameItem]; + } + elseif (\is_object($data)) + { + $data->{$nameItem} ??= new \stdClass(); + $data = &$data->{$nameItem}; + } } } if (\is_array($data)) @@ -109,20 +112,27 @@ public static function set(&$object, string $name, $value): void */ public static function remove(&$object, string $name): void { + if ('' === $name) + { + return; + } $names = explode('.', $name); $lastName = array_pop($names); $data = &$object; - foreach ($names as $nameItem) + if ($names) { - if (\is_array($data)) - { - $data[$nameItem] ??= []; - $data = &$data[$nameItem]; - } - elseif (\is_object($data)) + foreach ($names as $nameItem) { - $data->{$nameItem} ??= new \stdClass(); - $data = &$data->{$nameItem}; + if (\is_array($data)) + { + $data[$nameItem] ??= []; + $data = &$data[$nameItem]; + } + elseif (\is_object($data)) + { + $data->{$nameItem} ??= new \stdClass(); + $data = &$data->{$nameItem}; + } } } if (\is_array($data)) diff --git a/src/Util/Process.php b/src/Util/Process.php index fde7200211..997829cffc 100644 --- a/src/Util/Process.php +++ b/src/Util/Process.php @@ -6,9 +6,7 @@ class Process { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; public static function isTtySupported(): bool { diff --git a/src/Util/Process/ProcessAppContexts.php b/src/Util/Process/ProcessAppContexts.php index 2ee3efc17b..5fc4203511 100644 --- a/src/Util/Process/ProcessAppContexts.php +++ b/src/Util/Process/ProcessAppContexts.php @@ -9,6 +9,8 @@ */ class ProcessAppContexts { + use \Imi\Util\Traits\TStaticClass; + /** * 进程类型. */ @@ -28,8 +30,4 @@ class ProcessAppContexts * 当前进程脚本名称. */ public const SCRIPT_NAME = 'script_name'; - - private function __construct() - { - } } diff --git a/src/Util/Process/ProcessType.php b/src/Util/Process/ProcessType.php index 4941d95bfe..af21526284 100644 --- a/src/Util/Process/ProcessType.php +++ b/src/Util/Process/ProcessType.php @@ -9,6 +9,8 @@ */ class ProcessType { + use \Imi\Util\Traits\TStaticClass; + /** * master 进程. */ @@ -33,8 +35,4 @@ class ProcessType * 进程. */ public const PROCESS = 'process'; - - private function __construct() - { - } } diff --git a/src/Util/Random.php b/src/Util/Random.php index 278dbf7d8c..cc2325313d 100644 --- a/src/Util/Random.php +++ b/src/Util/Random.php @@ -7,8 +7,10 @@ /** * 随机生成一些东西的工具类. */ -abstract class Random +class Random { + use \Imi\Util\Traits\TStaticClass; + /** * 随机整数. */ diff --git a/src/Util/Stream/FileStream.php b/src/Util/Stream/FileStream.php index 6e150cf78b..26a20cae41 100644 --- a/src/Util/Stream/FileStream.php +++ b/src/Util/Stream/FileStream.php @@ -54,7 +54,7 @@ public function __construct($uri, string $mode = StreamMode::READ_WRITE) $this->stream = fopen($uri->__toString(), $mode); if (false === $this->stream) { - throw new \RuntimeException(sprintf('Open stream %s error', (string) $uri)); + throw new \RuntimeException(sprintf('Open stream %s error', (string) $uri)); // @codeCoverageIgnore } } } @@ -78,10 +78,12 @@ public function __toString() return stream_get_contents($this->stream); } + // @codeCoverageIgnoreStart catch (\Throwable $th) { return ''; } + // @codeCoverageIgnoreEnd } /** @@ -112,7 +114,7 @@ public function getSize() $stat = fstat($this->stream); if (false === $stat) { - throw new \RuntimeException('Get stream size error'); + throw new \RuntimeException('Get stream size error'); // @codeCoverageIgnore } return $stat['size']; @@ -126,7 +128,7 @@ public function tell() $result = ftell($this->stream); if (false === $result) { - throw new \RuntimeException('Stream tell error'); + throw new \RuntimeException('Stream tell error'); // @codeCoverageIgnore } return $result; @@ -157,7 +159,7 @@ public function seek($offset, $whence = \SEEK_SET) { if (-1 === fseek($this->stream, $offset, $whence)) { - throw new \RuntimeException('Seek stream error'); + throw new \RuntimeException('Seek stream error'); // @codeCoverageIgnore } } @@ -168,7 +170,7 @@ public function rewind(): void { if (!rewind($this->stream)) { - throw new \RuntimeException('Rewind stream failed'); + throw new \RuntimeException('Rewind stream failed'); // @codeCoverageIgnore } } @@ -196,7 +198,7 @@ public function write($string) $result = fwrite($this->stream, $string); if (false === $result) { - throw new \RuntimeException('Write stream failed'); + throw new \RuntimeException('Write stream failed'); // @codeCoverageIgnore } return $result; @@ -224,7 +226,7 @@ public function read($length) $result = fread($this->stream, $length); if (false === $result) { - throw new \RuntimeException('Read stream error'); + throw new \RuntimeException('Read stream error'); // @codeCoverageIgnore } return $result; @@ -238,7 +240,7 @@ public function getContents() $result = stream_get_contents($this->stream); if (false === $result) { - throw new \RuntimeException('Stream getContents error'); + throw new \RuntimeException('Stream getContents error'); // @codeCoverageIgnore } return $result; @@ -253,7 +255,7 @@ public function getMetadata($key = null) // @phpstan-ignore-next-line if (!$result) { - throw new \RuntimeException('Stream getMetadata error'); + throw new \RuntimeException('Stream getMetadata error'); // @codeCoverageIgnore } if (null === $key) { @@ -265,7 +267,7 @@ public function getMetadata($key = null) } else { - return null; + return null; // @codeCoverageIgnore } } diff --git a/src/Util/Stream/MemoryStream.php b/src/Util/Stream/MemoryStream.php index 06fd1a5ee7..b4f3fac0fd 100644 --- a/src/Util/Stream/MemoryStream.php +++ b/src/Util/Stream/MemoryStream.php @@ -76,7 +76,7 @@ public function tell() */ public function eof() { - return $this->position > $this->size; + return $this->position >= $this->size - 1; } /** @@ -99,7 +99,7 @@ public function seek($offset, $whence = \SEEK_SET) case \SEEK_SET: if ($offset < 0) { - throw new \RuntimeException('Offset failure'); + throw new \RuntimeException('Offset failure'); // @codeCoverageIgnore } $this->position = $offset; break; @@ -107,7 +107,7 @@ public function seek($offset, $whence = \SEEK_SET) $this->position += $offset; break; case \SEEK_END: - $this->position = $this->size - 1 + $offset; + $this->position = $this->size + $offset; break; } } @@ -136,7 +136,7 @@ public function write($string) $content = &$this->content; $position = &$this->position; $size = &$this->size; - if ($position === $size) + if ($position >= $size) { $content .= $string; } diff --git a/src/Util/Stream/StreamMode.php b/src/Util/Stream/StreamMode.php index de12315242..a0093c2330 100644 --- a/src/Util/Stream/StreamMode.php +++ b/src/Util/Stream/StreamMode.php @@ -9,6 +9,8 @@ */ class StreamMode { + use \Imi\Util\Traits\TStaticClass; + /** * 只读方式打开,指针指向开头. */ @@ -52,8 +54,4 @@ class StreamMode * 仅能用于本地文件。 */ public const CREATE_READ_WRITE = 'x+'; - - private function __construct() - { - } } diff --git a/src/Util/System.php b/src/Util/System.php index a8bc13e1f0..25c5f3e333 100644 --- a/src/Util/System.php +++ b/src/Util/System.php @@ -10,6 +10,8 @@ class System { /** * 获取本地 IP 列表. + * + * @codeCoverageIgnore */ public static function netLocalIp(): array { @@ -39,6 +41,11 @@ public static function netLocalIp(): array return $output; } + /** + * 获取 CPU 核心数. + * + * @codeCoverageIgnore + */ public static function getCpuCoresNum(): int { if (\PHP_OS_FAMILY === 'Windows') diff --git a/src/Util/Text.php b/src/Util/Text.php index 9c438ef8a1..e02b6ff2c4 100644 --- a/src/Util/Text.php +++ b/src/Util/Text.php @@ -11,9 +11,7 @@ */ class Text { - private function __construct() - { - } + use \Imi\Util\Traits\TStaticClass; /** * 字符串是否以另一个字符串开头. @@ -22,18 +20,7 @@ public static function startwith(string $string, string $compare, bool $caseSens { if ($caseSensitive) { - # if \PHP_VERSION_ID < 80000 - if (\PHP_VERSION_ID >= 80000) - { - return str_starts_with($string, $compare); - } - else - { - # endif - return str_starts_with($string, $compare); - # if \PHP_VERSION_ID < 80000 - } - # endif + return str_starts_with($string, $compare); } else { @@ -56,14 +43,20 @@ public static function endwith(string $string, string $compare, bool $caseSensit else { # endif - return $compare === strrchr($string, $compare); + return $compare === strrchr($string, $compare); // @codeCoverageIgnore # if \PHP_VERSION_ID < 80000 } # endif } else { - return 0 === substr_compare($compare, strrchr($string, $compare), 0, 0, true); + $needle = strrchr($string, $compare); + if (false === $needle) + { + return false; + } + + return 0 === substr_compare($compare, $needle, 0, 0, true); } } diff --git a/src/Util/Traits/TSingleton.php b/src/Util/Traits/TSingleton.php index 746e10e472..62eaa88ee7 100644 --- a/src/Util/Traits/TSingleton.php +++ b/src/Util/Traits/TSingleton.php @@ -9,6 +9,8 @@ */ trait TSingleton { + use \Imi\Util\Traits\TStaticClass; + /** * 实例对象 */ @@ -19,10 +21,6 @@ trait TSingleton */ protected static array $__instances = []; - private function __construct() - { - } - /** * 获取单例对象 * diff --git a/src/Util/Traits/TStaticClass.php b/src/Util/Traits/TStaticClass.php new file mode 100644 index 0000000000..38654ccc1f --- /dev/null +++ b/src/Util/Traits/TStaticClass.php @@ -0,0 +1,18 @@ +scheme = $scheme; diff --git a/src/Worker.php b/src/Worker.php index 33a36c4ec8..8920c7e951 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -8,6 +8,8 @@ class Worker { + use \Imi\Util\Traits\TStaticClass; + protected static ?IWorker $workerHandler = null; /** @@ -15,10 +17,6 @@ class Worker */ protected static bool $isInited = false; - private function __construct() - { - } - public static function setWorkerHandler(IWorker $workerHandler): void { static::$workerHandler = $workerHandler; diff --git a/src/functions.php b/src/functions.php index cf8d2fbe6d..9112ebe934 100644 --- a/src/functions.php +++ b/src/functions.php @@ -105,6 +105,8 @@ function cmd(string $cmd): string * 尝试使用 tty 模式执行命令,可以保持带颜色格式的输出 * 返回进程退出码 * + * @codeCoverageIgnore + * * @param string|array $commands */ function ttyExec($commands, ?float $timeout = null, ?Process &$process = null): int diff --git a/tests/phpunit.xml b/tests/phpunit.xml index bca9568549..be4aaf7a05 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -65,6 +65,7 @@ + diff --git a/tests/unit/BaseTest.php b/tests/unit/BaseTest.php index 15092570e3..27a6316084 100644 --- a/tests/unit/BaseTest.php +++ b/tests/unit/BaseTest.php @@ -47,7 +47,7 @@ protected function go(callable $callable, ?callable $finally = null, int $retry protected function php(string $phpFile, string $args = ''): string { - $cmd = \Imi\cmd('"' . \PHP_BINARY . "\" \"{$phpFile}\" {$args}"); + $cmd = \Imi\cmd(getTestPhpBinary() . " \"{$phpFile}\" {$args}"); return shell_exec("{$cmd}"); } diff --git a/tests/unit/Component/Bean/ReferenceBean.php b/tests/unit/Component/Bean/ReferenceBean.php index 461c0df4ec..c02fa0e75e 100644 --- a/tests/unit/Component/Bean/ReferenceBean.php +++ b/tests/unit/Component/Bean/ReferenceBean.php @@ -13,6 +13,11 @@ class ReferenceBean { private array $list = []; + public function add(int $a, int $b): int + { + return $a + $b; + } + public function testParams(int $a, ?int &$b): void { $b = $a; diff --git a/tests/unit/Component/Db/Classes/TestTransaction.php b/tests/unit/Component/Db/Classes/TestTransaction.php new file mode 100644 index 0000000000..ec9ea32a9d --- /dev/null +++ b/tests/unit/Component/Db/Classes/TestTransaction.php @@ -0,0 +1,89 @@ +userId; + } + + public function setUserId(?int $userId): self + { + $this->userId = $userId; + + return $this; + } + + /** + * @Column(virtual=true) + */ + protected ?int $userId2 = null; + + public function getUserId2(): ?int + { + return $this->userId2; + } + + public function setUserId2(?int $userId2): self + { + $this->userId2 = $userId2; + + return $this; + } +} diff --git a/tests/unit/Component/Performance/BaseDbTest.php b/tests/unit/Component/Performance/BaseDbTest.php index 0551f16930..6f77f4a3ae 100644 --- a/tests/unit/Component/Performance/BaseDbTest.php +++ b/tests/unit/Component/Performance/BaseDbTest.php @@ -13,6 +13,14 @@ abstract class BaseDbTest extends BaseTest { abstract public function getPoolName(): string; + public static function setUpBeforeClass(): void + { + if (isCodeCoverage()) + { + static::markTestSkipped(); + } + } + public function testTruncate(): void { App::set('DB_LOG', false); diff --git a/tests/unit/Component/Performance/ModelTest.php b/tests/unit/Component/Performance/ModelTest.php index 7894fe0e34..0cf6fff30b 100644 --- a/tests/unit/Component/Performance/ModelTest.php +++ b/tests/unit/Component/Performance/ModelTest.php @@ -15,6 +15,14 @@ */ class ModelTest extends BaseTest { + public static function setUpBeforeClass(): void + { + if (isCodeCoverage()) + { + static::markTestSkipped(); + } + } + public function testTruncate(): void { App::set('DB_LOG', false); diff --git a/tests/unit/Component/Server/TestServer.php b/tests/unit/Component/Server/TestServer.php new file mode 100644 index 0000000000..1e8b6ada64 --- /dev/null +++ b/tests/unit/Component/Server/TestServer.php @@ -0,0 +1,66 @@ + $id] = $args; + $db = Db::getInstance($this->poolName); + $stmt = $db->query('select * from tb_article where id = ' . $id); + $stmt->close(); + $this->assertTrue(true); + } + /** * @depends testInsert */ @@ -101,6 +113,29 @@ public function testQuery(array $args): void ], $stmt->fetchAll()); } + /** + * @depends testInsert + */ + public function testQueryAlias(array $args): void + { + ['id' => $id] = $args; + $result = Db::getInstance($this->poolName) + ->createQuery() + ->table('tb_article', 'a1') + ->where('a1.id', '=', $id) + ->select() + ->getArray(); + Assert::assertEquals([ + [ + 'id' => $id, + 'title' => 'title', + 'content' => 'content', + 'time' => '2019-06-21 00:00:00', + 'member_id' => 0, + ], + ], $result); + } + /** * @depends testInsert */ diff --git a/tests/unit/Component/Tests/Db/QueryCurdBaseTest.php b/tests/unit/Component/Tests/Db/QueryCurdBaseTest.php index 3027f3973c..d4c55916cd 100644 --- a/tests/unit/Component/Tests/Db/QueryCurdBaseTest.php +++ b/tests/unit/Component/Tests/Db/QueryCurdBaseTest.php @@ -6,6 +6,7 @@ use Imi\Db\Db; use Imi\Db\Mysql\Query\Lock\MysqlLock; +use Imi\Db\Query\Database; use Imi\Db\Query\Raw; use Imi\Test\BaseTest; use PHPUnit\Framework\Assert; @@ -496,4 +497,32 @@ public function testSetFieldExp(): void $this->assertEquals('replace into `test` set `a` = `a` + :fip1,`b` = `b` - :fdp2,`c` = c + :c', $query->buildReplaceSql()); $this->assertEquals([':fip1' => 4, ':fdp2' => 5, ':c' => 6], $query->getBinds()); } + + public function testDatabase(): void + { + $query = Db::query(); + + $database = new Database(); + $this->assertNull($database->getDatabase()); + $this->assertNull($database->getAlias()); + $this->assertEquals('', $database->toString($query)); + + $database->setDatabase('db_imi'); + $this->assertEquals('db_imi', $database->getDatabase()); + $this->assertNull($database->getAlias()); + $this->assertEquals('`db_imi`', $database->toString($query)); + + $database->setAlias('a'); + $this->assertEquals('db_imi', $database->getDatabase()); + $this->assertEquals('a', $database->getAlias()); + $this->assertEquals('`db_imi` as `a`', $database->toString($query)); + + $database->useRaw(true); + $this->assertTrue($database->isRaw()); + $database->setRawSQL('db_imi2'); + $this->assertEquals('(db_imi2) as `a`', $database->toString($query)); + $database->setAlias(null); + $this->assertNull($database->getAlias()); + $this->assertEquals('db_imi2', $database->toString($query)); + } } diff --git a/tests/unit/Component/Tests/Db/TransactionTest.php b/tests/unit/Component/Tests/Db/TransactionTest.php new file mode 100644 index 0000000000..2464eb99f3 --- /dev/null +++ b/tests/unit/Component/Tests/Db/TransactionTest.php @@ -0,0 +1,314 @@ +getObject(); + $db = Db::getInstance(); + $transaction = $db->getTransaction(); + try + { + $object->nestingCommit(); + $this->assertEquals(0, $transaction->getTransactionLevels()); + } + finally + { + if ($db->inTransaction()) + { + $transaction->rollBack(); + } + } + + // 在事务中,不自动提交事务 + $db->beginTransaction(); + $this->assertEquals(1, $transaction->getTransactionLevels()); + try + { + $object->nestingCommit(); + // 事务嵌套 + $this->assertEquals(2, $transaction->getTransactionLevels()); + $db->commit(); + $this->assertEquals(0, $transaction->getTransactionLevels()); + } + finally + { + if ($db->inTransaction()) + { + $transaction->rollBack(); + } + } + } + + public function testNestingRollback(): void + { + $object = $this->getObject(); + $db = Db::getInstance(); + $transaction = $db->getTransaction(); + $db->beginTransaction(); + $this->assertEquals(1, $transaction->getTransactionLevels()); + + try + { + $catched = false; + try + { + $object->nestingRollback(); + } + catch (\Throwable $th) + { + $catched = true; + $this->assertEquals('gg', $th->getMessage()); + $this->assertEquals(0, $transaction->getTransactionLevels()); + } + finally + { + if (!$catched) + { + $this->assertTrue(false); + } + } + } + finally + { + if ($db->inTransaction()) + { + $transaction->rollBack(); + } + } + } + + public function testRequirementCommit1(): void + { + $this->expectExceptionMessageMatches('/.+::.+ can not run without transactional/'); + $object = $this->getObject(); + $object->requirementCommit(); + } + + public function testRequirementCommit2(): void + { + $object = $this->getObject(); + $db = Db::getInstance(); + $transaction = $db->getTransaction(); + $db->beginTransaction(); + $this->assertEquals(1, $transaction->getTransactionLevels()); + try + { + $object->requirementCommit(); + // 事务嵌套 + $this->assertEquals(1, $transaction->getTransactionLevels()); + $db->commit(); + $this->assertEquals(0, $transaction->getTransactionLevels()); + } + finally + { + if ($db->inTransaction()) + { + $transaction->rollBack(); + } + } + } + + public function testRequirementRollback(): void + { + $object = $this->getObject(); + $db = Db::getInstance(); + $transaction = $db->getTransaction(); + $db->beginTransaction(); + $this->assertEquals(1, $transaction->getTransactionLevels()); + + try + { + $catched = false; + try + { + $object->requirementRollback(); + } + catch (\Throwable $th) + { + $catched = true; + $this->assertEquals('gg', $th->getMessage()); + $this->assertEquals(0, $transaction->getTransactionLevels()); + } + finally + { + if (!$catched) + { + $this->assertTrue(false); + } + } + } + finally + { + if ($db->inTransaction()) + { + $transaction->rollBack(); + } + } + } + + public function testAutoCommit(): void + { + // 不在事务中,开启事务并提交事务 + $object = $this->getObject(); + $db = Db::getInstance(); + $transaction = $db->getTransaction(); + try + { + $object->autoCommit(); + $this->assertEquals(0, $transaction->getTransactionLevels()); + } + finally + { + if ($db->inTransaction()) + { + $transaction->rollBack(); + } + } + + // 在事务中,不自动提交事务 + $db->beginTransaction(); + $this->assertEquals(1, $transaction->getTransactionLevels()); + try + { + $object->autoCommit(); + // 事务嵌套 + $this->assertEquals(1, $transaction->getTransactionLevels()); + $db->commit(); + $this->assertEquals(0, $transaction->getTransactionLevels()); + } + finally + { + if ($db->inTransaction()) + { + $transaction->rollBack(); + } + } + } + + public function testAutoRollback(): void + { + $object = $this->getObject(); + $db = Db::getInstance(); + $transaction = $db->getTransaction(); + + try + { + $catched = false; + try + { + $object->autoRollback(); + } + catch (\Throwable $th) + { + $catched = true; + $this->assertEquals('gg', $th->getMessage()); + $this->assertEquals(0, $transaction->getTransactionLevels()); + } + finally + { + if (!$catched) + { + $this->assertTrue(false); + } + } + } + finally + { + if ($db->inTransaction()) + { + $transaction->rollBack(); + } + } + } + + public function testRollbackPart1(): void + { + $object = $this->getObject(); + $db = Db::getInstance(); + $transaction = $db->getTransaction(); + $db->beginTransaction(); + $this->assertEquals(1, $transaction->getTransactionLevels()); + + try + { + $catched = false; + try + { + $object->rollbackPart1(); + } + catch (\Throwable $th) + { + $catched = true; + $this->assertEquals('gg', $th->getMessage()); + $this->assertEquals(1, $transaction->getTransactionLevels()); + } + finally + { + if (!$catched) + { + $this->assertTrue(false); + } + } + } + finally + { + if ($db->inTransaction()) + { + $transaction->rollBack(); + } + } + } + + public function testRollbackPartAll(): void + { + $object = $this->getObject(); + $db = Db::getInstance(); + $transaction = $db->getTransaction(); + $db->beginTransaction(); + $this->assertEquals(1, $transaction->getTransactionLevels()); + + try + { + $catched = false; + try + { + $object->rollbackPartAll(); + } + catch (\Throwable $th) + { + $catched = true; + $this->assertEquals('gg', $th->getMessage()); + $this->assertEquals(0, $transaction->getTransactionLevels()); + } + finally + { + if (!$catched) + { + $this->assertTrue(false); + } + } + } + finally + { + if ($db->inTransaction()) + { + $transaction->rollBack(); + } + } + } +} diff --git a/tests/unit/Component/Tests/EnvTest.php b/tests/unit/Component/Tests/EnvTest.php index c86e794151..286c670fd5 100644 --- a/tests/unit/Component/Tests/EnvTest.php +++ b/tests/unit/Component/Tests/EnvTest.php @@ -11,6 +11,23 @@ class EnvTest extends BaseTest { + public function testFunctionImiGetEnv(): void + { + $this->assertEquals(123, imiGetEnv('A')); + $this->assertEquals('imi', imiGetEnv('E')); + $this->assertEquals('123', imiGetEnv('A', 'default')); + $this->assertEquals(123, imiGetEnv('A', 0)); + $this->assertEquals(123.0, imiGetEnv('A', 3.14)); + $this->assertEquals('123', imiGetEnv('A', false)); + $this->assertFalse(imiGetEnv('B', false)); + $this->assertTrue(imiGetEnv('BOOL_TRUE', false)); + $this->assertFalse(imiGetEnv('BOOL_FALSE', false)); + $this->assertEquals(['1', '2', '3'], imiGetEnv('C', [])); + $this->assertEquals(['4', '5', '6'], imiGetEnv('D', [])); + $this->assertNull(imiGetEnv('NULL_VALUE')); + $this->assertNull(imiGetEnv('NULL_VALUE', 666)); + } + public function testFunctionEnv(): void { $this->assertEquals(123, env('A')); diff --git a/tests/unit/Component/Tests/FunctionTest.php b/tests/unit/Component/Tests/FunctionTest.php index 0a718525b5..3dad5d1f12 100644 --- a/tests/unit/Component/Tests/FunctionTest.php +++ b/tests/unit/Component/Tests/FunctionTest.php @@ -11,17 +11,25 @@ class FunctionTest extends BaseTest { + public function testImiCallable(): void + { + $callable = imiCallable(static fn () => 1); + $this->assertEquals(1, $callable()); + } + public function testDump(): void { $cmd = [ - \PHP_BINARY, + ...getTestPhpBinaryArray(), File::path(\dirname(Imi::getNamespacePath('Imi')), 'src', 'Cli', 'bin', 'imi-cli'), '--app-namespace', 'Imi\Test\Component', 'TestTool/testDump', ]; - $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi'))); + $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi')), [ + 'IMI_CODE_COVERAGE_NAME' => getCodeCoverageName(), + ]); $process->mustRun(); $output = $process->getOutput(); $this->assertTrue(false !== preg_match(<<<'STR' diff --git a/tests/unit/Component/Tests/HotUpdate/BaseMonitorTest.php b/tests/unit/Component/Tests/HotUpdate/BaseMonitorTest.php new file mode 100644 index 0000000000..f4d736ebde --- /dev/null +++ b/tests/unit/Component/Tests/HotUpdate/BaseMonitorTest.php @@ -0,0 +1,45 @@ +getMonitor([$path], [$excludePath]); + $this->assertFalse($monitor->isChanged()); + + $file = $path . \DIRECTORY_SEPARATOR . 'test1.txt'; + file_put_contents($file, 'test1'); + $this->assertTrue($monitor->isChanged()); + $this->assertEquals([$file], $monitor->getChangedFiles()); + $this->assertFalse($monitor->isChanged()); + + unlink($file); + $this->assertTrue($monitor->isChanged()); + $this->assertEquals([$file], $monitor->getChangedFiles()); + $this->assertFalse($monitor->isChanged()); + + mkdir($excludePath, 0777, true); + $this->assertFalse($monitor->isChanged()); + + $file = $excludePath . \DIRECTORY_SEPARATOR . 'test1.txt'; + file_put_contents($file, 'test1'); + $this->assertFalse($monitor->isChanged()); + } + + abstract protected function getMonitor(array $includePaths, array $excludePaths = []): IMonitor; +} diff --git a/tests/unit/Component/Tests/HotUpdate/FileMTimeTest.php b/tests/unit/Component/Tests/HotUpdate/FileMTimeTest.php new file mode 100644 index 0000000000..db7ae74d45 --- /dev/null +++ b/tests/unit/Component/Tests/HotUpdate/FileMTimeTest.php @@ -0,0 +1,16 @@ +id); $this->assertEquals(1, $record->amount); } + + public function testAnnotationDDL(): void + { + $ddl = new DDL(null, '1+1'); + $this->assertEquals('1+1', $ddl->getRawSql()); + + $ddl = new DDL(null, '1+1', static fn (string $sql): string => '2' . $sql); + $this->assertEquals('21+1', $ddl->getRawSql()); + } + + public function testAnnotationExtractProperty(): void + { + $record = TestJsonExtractProperty::newInstance(); + $record->jsonData = ['ex' => ['userId' => 123]]; + $record->insert(); + $record2 = TestJsonExtractProperty::find($record->id); + $this->assertNotNull($record2); + // @phpstan-ignore-next-line + $this->assertEquals($record->jsonData, $record2->jsonData->toArray()); + $this->assertEquals(123, $record2->userId); + $this->assertEquals(123, $record2->userId2); + + $record = TestJsonExtractProperty::newInstance(); + $record->jsonData = []; + $record->insert(); + $record2 = TestJsonExtractProperty::find($record->id); + $this->assertNotNull($record2); + // @phpstan-ignore-next-line + $this->assertEquals($record->jsonData, $record2->jsonData->toArray()); + $this->assertNull($record2->userId); + $this->assertNull($record2->userId2); + } + + public function testAnnotationEncodeDecode(): void + { + $record = TestJsonEncodeDecode1::newInstance(); + $record->jsonData = ['name' => '宇润']; + $record->insert(); + $record2 = TestJsonEncodeDecode1::find($record->id); + $this->assertNotNull($record2); + $this->assertIsArray($record2->jsonData); + $this->assertEquals('宇润', $record2->jsonData['name'] ?? null); + + $record = TestJsonEncodeDecode2::newInstance(); + $record->jsonData = ['name' => '宇润']; + $record->insert(); + $record2 = TestJsonEncodeDecode2::find($record->id); + $this->assertNotNull($record2); + $this->assertIsObject($record2->jsonData); + $this->assertEquals('宇润', $record2->jsonData->name ?? null); + } } diff --git a/tests/unit/Component/Tests/Server/DataParser/BaseDataParserTest.php b/tests/unit/Component/Tests/Server/DataParser/BaseDataParserTest.php new file mode 100644 index 0000000000..7e48b73800 --- /dev/null +++ b/tests/unit/Component/Tests/Server/DataParser/BaseDataParserTest.php @@ -0,0 +1,29 @@ +getParser(); + $encodeData = $this->getEncodeData(); + $decodeData = $this->getDecodeData(); + $this->assertEquals($encodeData, $parser->encode($decodeData)); + $this->assertEquals($decodeData, $parser->decode($encodeData)); + } + + abstract protected function getParser(): IParser; + + /** + * @return mixed + */ + abstract protected function getDecodeData(); + + abstract protected function getEncodeData(): string; +} diff --git a/tests/unit/Component/Tests/Server/DataParser/JsonArrayParserTest.php b/tests/unit/Component/Tests/Server/DataParser/JsonArrayParserTest.php new file mode 100644 index 0000000000..316609f273 --- /dev/null +++ b/tests/unit/Component/Tests/Server/DataParser/JsonArrayParserTest.php @@ -0,0 +1,32 @@ + 'imi', + 'creator' => '宇润', + ]; + } + + protected function getEncodeData(): string + { + return json_encode($this->getDecodeData(), \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); + } +} diff --git a/tests/unit/Component/Tests/Server/DataParser/JsonObjectParserTest.php b/tests/unit/Component/Tests/Server/DataParser/JsonObjectParserTest.php new file mode 100644 index 0000000000..5f28916ab5 --- /dev/null +++ b/tests/unit/Component/Tests/Server/DataParser/JsonObjectParserTest.php @@ -0,0 +1,33 @@ +name = 'imi'; + $object->creator = '宇润'; + + return $object; + } + + protected function getEncodeData(): string + { + return json_encode($this->getDecodeData(), \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); + } +} diff --git a/tests/unit/Component/Tests/ToolTest.php b/tests/unit/Component/Tests/ToolTest.php index 23925c463d..5794117211 100644 --- a/tests/unit/Component/Tests/ToolTest.php +++ b/tests/unit/Component/Tests/ToolTest.php @@ -17,14 +17,16 @@ class ToolTest extends BaseTest public function testCoExit(): void { $cmd = [ - \PHP_BINARY, + ...getTestPhpBinaryArray(), File::path(\dirname(Imi::getNamespacePath('Imi')), 'src', 'Cli', 'bin', 'imi-cli'), '--app-namespace', 'Imi\Test\Component', 'TestTool/test', ]; - $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi'))); + $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi')), [ + 'IMI_CODE_COVERAGE_NAME' => getCodeCoverageName(), + ]); $process->mustRun(); $this->assertEquals(0, $process->getExitCode(), $process->getCommandLine()); @@ -32,7 +34,9 @@ public function testCoExit(): void $cmd[] = '--code'; $cmd[] = $code = random_int(0, 255); - $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi'))); + $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi')), [ + 'IMI_CODE_COVERAGE_NAME' => getCodeCoverageName(), + ]); $process->run(); $this->assertEquals($code, $process->getExitCode(), $process->getCommandLine()); } @@ -61,7 +65,7 @@ public function boolProvider(): \Generator public function testBool($suffix, array $results): void { $cmd = [ - \PHP_BINARY, + ...getTestPhpBinaryArray(), File::path(\dirname(Imi::getNamespacePath('Imi')), 'src', 'Cli', 'bin', 'imi-cli'), '--app-namespace', 'Imi\Test\Component', @@ -76,7 +80,9 @@ public function testBool($suffix, array $results): void { $cmd[] = $suffix; } - $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi'))); + $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi')), [ + 'IMI_CODE_COVERAGE_NAME' => getCodeCoverageName(), + ]); $process->mustRun(); $this->assertEquals(0, $process->getExitCode()); $output = $process->getOutput(); @@ -105,7 +111,7 @@ public function argumentProvider(): \Generator public function testArgument($suffix, array $results): void { $cmd = [ - \PHP_BINARY, + ...getTestPhpBinaryArray(), File::path(\dirname(Imi::getNamespacePath('Imi')), 'src', 'Cli', 'bin', 'imi-cli'), '--app-namespace', 'Imi\Test\Component', @@ -120,7 +126,9 @@ public function testArgument($suffix, array $results): void { $cmd[] = $suffix; } - $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi'))); + $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi')), [ + 'IMI_CODE_COVERAGE_NAME' => getCodeCoverageName(), + ]); $process->mustRun(); $this->assertEquals(0, $process->getExitCode()); $output = $process->getOutput(); @@ -152,7 +160,7 @@ public function negatableProvider(): \Generator public function testNegatable($suffix, array $results): void { $cmd = [ - \PHP_BINARY, + ...getTestPhpBinaryArray(), File::path(\dirname(Imi::getNamespacePath('Imi')), 'src', 'Cli', 'bin', 'imi-cli'), '--app-namespace', 'Imi\Test\Component', @@ -167,7 +175,9 @@ public function testNegatable($suffix, array $results): void { $cmd[] = $suffix; } - $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi'))); + $process = new Process($cmd, \dirname(Imi::getNamespacePath('Imi')), [ + 'IMI_CODE_COVERAGE_NAME' => getCodeCoverageName(), + ]); $process->mustRun(); $this->assertEquals(0, $process->getExitCode()); $output = $process->getOutput(); diff --git a/tests/unit/Component/Tests/Util/ArrayDataTest.php b/tests/unit/Component/Tests/Util/ArrayDataTest.php index 2b7d771e1c..c0ceef9fd3 100644 --- a/tests/unit/Component/Tests/Util/ArrayDataTest.php +++ b/tests/unit/Component/Tests/Util/ArrayDataTest.php @@ -29,9 +29,22 @@ public function testArrayData(): void ]; $data = new ArrayData($rawData); + // @phpstan-ignore-next-line + $this->assertFalse($data->get(1)); + $this->assertFalse($data->get('name.a')); + + $this->assertEquals($rawData, $data->get()); + $this->assertEquals($rawData, $data->getRawData()); + + $data->set([ + 'data3' => 123, + ]); + $rawData['data3'] = 123; + $this->assertEquals($rawData, $data->get()); $this->assertEquals($rawData, $data->getRawData()); - $this->assertEquals(5, $data->length()); - $this->assertCount(5, $data); + + $this->assertEquals(6, $data->length()); + $this->assertCount(6, $data); foreach ($data as $k => $v) { $this->assertEquals($rawData[$k], $v); @@ -77,6 +90,10 @@ public function testArrayData(): void 'b' => 1, ], $data->get('a')); + // @phpstan-ignore-next-line + $this->assertFalse($data->remove(1)); + $this->assertTrue($data->remove('data1.id')); + $data->set([ 'a' => [ 'c' => 2, @@ -95,6 +112,8 @@ public function testArrayData(): void 'c' => 2, ], $data->get('a')); + // @phpstan-ignore-next-line + $this->assertFalse($data->setVal(1)); $data->setVal('x.y', 1); $this->assertEquals(1, $data->x['y']); $this->assertEquals($data->x['y'], $data['x.y']); @@ -121,5 +140,8 @@ public function testArrayData(): void $data->clear(); $this->assertEmpty($data->getRawData()); + + $data[] = 1; + $this->assertEquals([1], $data->getRawData()); } } diff --git a/tests/unit/Component/Tests/Util/ArrayListTest.php b/tests/unit/Component/Tests/Util/ArrayListTest.php index eb10e8ab0f..169ba8225d 100644 --- a/tests/unit/Component/Tests/Util/ArrayListTest.php +++ b/tests/unit/Component/Tests/Util/ArrayListTest.php @@ -54,8 +54,9 @@ public function testArrayList(): void $this->assertEquals(json_encode($list), json_encode($arrayList)); // get - $item = $arrayList[1] ?? null; - $this->assertEquals($list[1], $item); + $this->assertEquals($list[1], $arrayList[1]); + + $this->assertNull($arrayList[114514]); // set try diff --git a/tests/unit/Component/Tests/Util/ArrayUtilTest.php b/tests/unit/Component/Tests/Util/ArrayUtilTest.php index b4841f3bf6..a055fd580a 100644 --- a/tests/unit/Component/Tests/Util/ArrayUtilTest.php +++ b/tests/unit/Component/Tests/Util/ArrayUtilTest.php @@ -92,6 +92,7 @@ public function testRecursiveMerge(): void 300 => 'c', ], ]; + $arr3 = ['imi']; $actual = [ 'a' => [ 'a-1' => [ @@ -110,8 +111,9 @@ public function testRecursiveMerge(): void 200 => 'b', 300 => 'c', ], + 'imi', ]; - $result = ArrayUtil::recursiveMerge($arr1, $arr2); + $result = ArrayUtil::recursiveMerge($arr1, $arr2, [], $arr3); $this->assertEquals($actual, $result); } diff --git a/tests/unit/Component/Tests/Util/ClassObjectTest.php b/tests/unit/Component/Tests/Util/ClassObjectTest.php index 9a7b1410a0..533ed6166e 100644 --- a/tests/unit/Component/Tests/Util/ClassObjectTest.php +++ b/tests/unit/Component/Tests/Util/ClassObjectTest.php @@ -47,6 +47,19 @@ public function testConvertArgsToKV(): void $args = [1, 2]; $params = ReflectionContainer::getMethodReflection($class, $method)->getParameters(); + // convertArgsToKV + // $keepNotExistArgs = true + $this->assertEquals([ + 'a' => 1, + 'b' => 2, + 'c' => 'imi.com', + ], ClassObject::convertArgsToKV($class, '__construct', $args)); + // $keepNotExistArgs = false + $this->assertEquals([ + 'a' => 1, + 'b' => 2, + ], ClassObject::convertArgsToKV($class, '__construct', $args, false)); + // convertArgsToKV // $keepNotExistArgs = true $this->assertEquals([ @@ -67,11 +80,20 @@ public function testConvertArgsToKV(): void 'b' => 2, 'c' => 'imi.com', ], $kv); + $this->assertEquals([], ClassObject::convertKVToArray([], [])); $this->assertEquals([ 1, 2, 'imi.com', ], ClassObject::convertKVToArray($params, $kv)); + try + { + ClassObject::convertKVToArray($params, []); + } + catch (\InvalidArgumentException $e) + { + $this->assertStringMatchesFormat('Argument %s of %s::__construct() does not found', $e->getMessage()); + } // $keepNotExistArgs = false $kv = ClassObject::convertArrayToKV($params, $args, false); @@ -84,6 +106,17 @@ public function testConvertArgsToKV(): void 2, 'imi.com', ], ClassObject::convertKVToArray($params, $kv)); + + $params = ReflectionContainer::getMethodReflection($class, 'noParam')->getParameters(); + $kv = ClassObject::convertArrayToKV($params, []); + $this->assertEquals([], $kv); + + $params = ReflectionContainer::getMethodReflection($class, 'variadic')->getParameters(); + $kv = ClassObject::convertArrayToKV($params, ['a', 'b']); + $this->assertEquals(['params' => [ + 'a', + 'b', + ]], $kv); } /** @@ -121,5 +154,9 @@ public function testNewInstance(): void $this->assertEquals(111, $object->a); $this->assertEquals(222, $object->b); $this->assertEquals('333', $object->c); + + $class = \Imi\Test\Component\Util\ClassObject\TestNoConstrauct::class; + $object = ClassObject::newInstance($class, []); + $this->assertInstanceOf($class, $object); } } diff --git a/tests/unit/Component/Tests/Util/DateTimeTest.php b/tests/unit/Component/Tests/Util/DateTimeTest.php index a5299b2171..1ac19b2d17 100644 --- a/tests/unit/Component/Tests/Util/DateTimeTest.php +++ b/tests/unit/Component/Tests/Util/DateTimeTest.php @@ -23,4 +23,71 @@ public function testGetSecondsByInterval(): void $this->assertTrue($sec <= 1); }, null, 3); } + + public function testGetYesterday(): void + { + $yesterday = date('Y-m-d', strtotime('-1 day')); + $this->assertEquals($yesterday, DateTime::getYesterday('Y-m-d')); + $this->assertGreaterThanOrEqual(strtotime($yesterday), $ts = DateTime::getYesterday()); + $this->assertLessThanOrEqual(strtotime($yesterday) + 86399, $ts); + + $timestamp = strtotime('2018-06-21 12:34:56'); + $this->assertEquals('2018-06-20 12:34:56', DateTime::getYesterday('Y-m-d H:i:s', $timestamp)); + } + + public function testGetTomorrow(): void + { + $tomorrow = date('Y-m-d', strtotime('+1 day')); + $this->assertEquals($tomorrow, DateTime::getTomorrow('Y-m-d')); + $this->assertGreaterThanOrEqual(strtotime($tomorrow), $ts = DateTime::getTomorrow()); + $this->assertLessThanOrEqual(strtotime($tomorrow) + 86399, $ts); + + $timestamp = strtotime('2018-06-21 12:34:56'); + $this->assertEquals('2018-06-22 12:34:56', DateTime::getTomorrow('Y-m-d H:i:s', $timestamp)); + } + + public function testGetNextWeek(): void + { + $this->assertEquals(DateTime::getNextWeek(), DateTime::getNextWeek()); + + $timestamp = strtotime('2018-06-18 12:34:56'); + $nextDateTime = '2018-06-25 12:34:56'; + for ($i = 0; $i < 7; ++$i) + { + $this->assertEquals($nextDateTime, DateTime::getNextWeek(1, 'Y-m-d H:i:s', $timestamp), 'Wrong next week: ' . date('Y-m-d H:i:s', $timestamp)); + $this->assertEquals(strtotime($nextDateTime), DateTime::getNextWeek(1, null, $timestamp)); + $timestamp += 86400; + } + } + + public function testGetPrevWeek(): void + { + $this->assertEquals(DateTime::getPrevWeek(), DateTime::getPrevWeek()); + + $timestamp = strtotime('2018-06-18 12:34:56'); + $lastDateTime = '2018-06-11 12:34:56'; + for ($i = 0; $i < 7; ++$i) + { + $this->assertEquals($lastDateTime, DateTime::getPrevWeek(1, 'Y-m-d H:i:s', $timestamp), 'Wrong last week: ' . date('Y-m-d H:i:s', $timestamp)); + $this->assertEquals(strtotime($lastDateTime), DateTime::getPrevWeek(1, null, $timestamp)); + $timestamp += 86400; + } + } + + public function testGetWeekOfMonth(): void + { + $this->assertEquals(DateTime::getWeekOfMonth(), DateTime::getWeekOfMonth()); + $this->assertEquals(4, DateTime::getWeekOfMonth(strtotime('2018-06-21 12:34:56'))); + $this->assertEquals(1, DateTime::getWeekOfMonth(strtotime('2023-01-01'))); + $this->assertEquals(5, DateTime::getWeekOfMonth(strtotime('2023-05-30'))); + } + + public function testGetMonthWeekCount(): void + { + $this->assertEquals(5, DateTime::getMonthWeekCount(2018, 6)); + $this->assertEquals(4, DateTime::getMonthWeekCount(2021, 2)); + $this->assertEquals(6, DateTime::getMonthWeekCount(2023, 1)); + $this->assertEquals(5, DateTime::getMonthWeekCount(2023, 2)); + $this->assertEquals(5, DateTime::getMonthWeekCount(2023, 5)); + } } diff --git a/tests/unit/Component/Tests/Util/DelayBeanCallableTest.php b/tests/unit/Component/Tests/Util/DelayBeanCallableTest.php new file mode 100644 index 0000000000..5ac022a82f --- /dev/null +++ b/tests/unit/Component/Tests/Util/DelayBeanCallableTest.php @@ -0,0 +1,43 @@ +assertEquals('ReferenceBean', $callable->getBeanName()); + $this->assertEquals('add', $callable->getMethodName()); + $this->assertEquals(3, $callable(1, 2)); + } + + public function testDelayBeanCallableReference(): void + { + $callable = new DelayBeanCallable('ReferenceBean', 'testReturnValue', [__METHOD__]); + $this->assertEquals('ReferenceBean', $callable->getBeanName()); + $this->assertEquals('testReturnValue', $callable->getMethodName()); + $callable()[] = 1; + $list = &$callable(); + $this->assertEquals([1], $list); + $list[] = 2; + $list = $callable(); + $this->assertEquals([1, 2], $list); + } + + public function testSerialize(): void + { + $callable = new DelayBeanCallable('ReferenceBean', 'add'); + $str = serialize($callable); + $this->assertNotEmpty($str); + $callable2 = unserialize($str); + $this->assertEquals('ReferenceBean', $callable2->getBeanName()); + $this->assertEquals('add', $callable2->getMethodName()); + $this->assertEquals(3, $callable2(1, 2)); + } +} diff --git a/tests/unit/Component/Tests/Util/DelayClassCallableTest.php b/tests/unit/Component/Tests/Util/DelayClassCallableTest.php new file mode 100644 index 0000000000..d69fdf1b8e --- /dev/null +++ b/tests/unit/Component/Tests/Util/DelayClassCallableTest.php @@ -0,0 +1,44 @@ +assertEquals(ReferenceBean::class, $callable->getClassName()); + $this->assertEquals('add', $callable->getMethodName()); + $this->assertEquals(3, $callable(1, 2)); + } + + public function testDelayClassCallableReference(): void + { + $callable = new DelayClassCallable(ReferenceBean::class, 'testReturnValue'); + $this->assertEquals(ReferenceBean::class, $callable->getClassName()); + $this->assertEquals('testReturnValue', $callable->getMethodName()); + $callable()[] = 1; + $list = &$callable(); + $this->assertEquals([1], $list); + $list[] = 2; + $list = $callable(); + $this->assertEquals([1, 2], $list); + } + + public function testSerialize(): void + { + $callable = new DelayClassCallable(ReferenceBean::class, 'add'); + $str = serialize($callable); + $this->assertNotEmpty($str); + $callable2 = unserialize($str); + $this->assertEquals(ReferenceBean::class, $callable2->getClassName()); + $this->assertEquals('add', $callable2->getMethodName()); + $this->assertEquals(3, $callable2(1, 2)); + } +} diff --git a/tests/unit/Component/Tests/Util/DelayServerBeanCallableTest.php b/tests/unit/Component/Tests/Util/DelayServerBeanCallableTest.php new file mode 100644 index 0000000000..23ecb85b98 --- /dev/null +++ b/tests/unit/Component/Tests/Util/DelayServerBeanCallableTest.php @@ -0,0 +1,60 @@ + TestServer::class]); + RequestContext::set('server', $server); + } + + public static function tearDownAfterClass(): void + { + RequestContext::unset('server'); + } + + public function testDelayServerBeanCallable(): void + { + $callable = new DelayServerBeanCallable(__CLASS__, 'ReferenceBean', 'add'); + $this->assertEquals('ReferenceBean', $callable->getBeanName()); + $this->assertEquals('add', $callable->getMethodName()); + $this->assertEquals(3, $callable(1, 2)); + + $callable = new DelayServerBeanCallable(RequestContext::get('server'), 'ReferenceBean', 'add'); + $this->assertEquals(3, $callable(1, 2)); + } + + public function testDelayServerBeanCallableReference(): void + { + $callable = new DelayServerBeanCallable(__CLASS__, 'ReferenceBean', 'testReturnValue', [__METHOD__]); + $this->assertEquals('ReferenceBean', $callable->getBeanName()); + $this->assertEquals('testReturnValue', $callable->getMethodName()); + $callable()[] = 1; + $list = &$callable(); + $this->assertEquals([1], $list); + $list[] = 2; + $list = $callable(); + $this->assertEquals([1, 2], $list); + } + + public function testSerialize(): void + { + $callable = new DelayServerBeanCallable(__CLASS__, 'ReferenceBean', 'add'); + $str = serialize($callable); + $this->assertNotEmpty($str); + $callable2 = unserialize($str); + $this->assertEquals('ReferenceBean', $callable2->getBeanName()); + $this->assertEquals('add', $callable2->getMethodName()); + $this->assertEquals(3, $callable2(1, 2)); + } +} diff --git a/tests/unit/Component/Tests/Util/DocBlockTest.php b/tests/unit/Component/Tests/Util/DocBlockTest.php new file mode 100644 index 0000000000..38b5870a52 --- /dev/null +++ b/tests/unit/Component/Tests/Util/DocBlockTest.php @@ -0,0 +1,34 @@ +assertInstanceOf(DocBlockFactory::class, DocBlock::getFactory()); + } + + /** + * test. + */ + public function testGetDocBlock(): void + { + $block = DocBlock::getDocBlock(<<<'DATA' + /** + * @param int $a + */ + DATA); + $this->assertInstanceOf(RealDocBlock::class, $block); + $tags = $block->getTags(); + $this->assertCount(1, $tags); + $this->assertEquals('param', $tags[0]->getName()); + } +} diff --git a/tests/unit/Component/Tests/Util/ExpiredStorageTest.php b/tests/unit/Component/Tests/Util/ExpiredStorageTest.php index ae7694ff81..575ee34030 100644 --- a/tests/unit/Component/Tests/Util/ExpiredStorageTest.php +++ b/tests/unit/Component/Tests/Util/ExpiredStorageTest.php @@ -16,16 +16,19 @@ public function testExpiredStorage(): void ]); $this->assertTrue($storage->isset('a')); $this->assertEquals(123, $storage->get('a', null, $item)); + $this->assertGreaterThan(0, $item->getLastModifyTime()); $this->assertEquals(0, $item->getTTL()); $this->assertEquals(123, $item->getValue()); $storage->set('a', 456, 0.1); $this->assertEquals(456, $storage->get('a', null, $item)); + $this->assertGreaterThan(0, $item->getLastModifyTime()); $this->assertFalse($item->isExpired()); $this->assertEquals(0.1, $item->getTTL()); $this->assertEquals(456, $item->getValue()); usleep(110_000); $this->assertEquals('default', $storage->get('a', 'default', $item)); + $this->assertGreaterThan(0, $item->getLastModifyTime()); $this->assertTrue($item->isExpired()); $this->assertEquals(0.1, $item->getTTL()); $this->assertEquals(456, $item->getValue()); diff --git a/tests/unit/Component/Tests/Util/FileTest.php b/tests/unit/Component/Tests/Util/FileTest.php index a0cb097eb8..2d70600f4e 100644 --- a/tests/unit/Component/Tests/Util/FileTest.php +++ b/tests/unit/Component/Tests/Util/FileTest.php @@ -18,6 +18,7 @@ class FileTest extends BaseTest */ public function testPath(): void { + $this->assertEquals('', File::path()); $path = 'http://www.baidu.com/a/b.jpg'; $this->assertEquals($path, File::path('http://www.baidu.com', 'a', 'b.jpg')); $this->assertEquals($path, File::path('http://www.baidu.com/', 'a', 'b.jpg')); @@ -50,6 +51,8 @@ public function testPath(): void */ public function testEnum(): void { + $this->assertEquals([], File::enum('not file')); + $path = File::path(\dirname(__DIR__, 2) . '/Util/File'); $expectedFiles = [ ['pathName' => File::path($path, '1.txt'), 'pathName2' => File::path($path, '1.txt'), 'fileName' => '1.txt'], @@ -75,6 +78,9 @@ public function testEnum(): void */ public function testEnumAll(): void { + $result = File::enumAll('not file'); + $this->assertEquals(0, iterator_count($result)); + $path = \dirname(__DIR__, 2) . '/Util/File'; $expectedFiles = [ ['pathName' => File::path($path, '1.txt'), 'pathName2' => File::path($path, '1.txt'), 'fileName' => '1.txt'], @@ -103,6 +109,9 @@ public function testEnumAll(): void */ public function testEnumPHPFile(): void { + $result = File::enumPHPFile('not file'); + $this->assertEquals(0, iterator_count($result)); + $path = \dirname(__DIR__, 2) . '/Util/File'; $expectedFiles = [ File::path($path, '2.php'), @@ -122,6 +131,57 @@ public function testEnumPHPFile(): void */ public function testEnumFile(): void { + $result = File::enumFile('not file'); + $this->assertFalse($result->getReturn()); + + $path = \dirname(__DIR__, 2) . '/Util/File'; + $expectedFiles = [ + ['path' => $path, 'pathName' => File::path($path, '1.txt'), 'pathName2' => File::path($path, '1.txt'), 'fileName' => '1.txt'], + ['path' => $path, 'pathName' => File::path($path, '2.php'), 'pathName2' => File::path($path, '2.php'), 'fileName' => '2.php'], + ['path' => $path . \DIRECTORY_SEPARATOR . 'a', 'pathName' => File::path($path, 'a', 'a-1'), 'pathName2' => File::path($path, 'a', 'a-1'), 'fileName' => 'a-1'], + ['path' => $path, 'pathName' => File::path($path, 'a'), 'pathName2' => File::path($path, 'a'), 'fileName' => 'a'], + ['path' => $path . \DIRECTORY_SEPARATOR . 'a' . \DIRECTORY_SEPARATOR . 'a-1', 'pathName' => File::path($path, 'a', 'a-1', 'a-1.txt'), 'pathName2' => File::path($path, 'a', 'a-1', 'a-1.txt'), 'fileName' => 'a-1.txt'], + ['path' => $path . \DIRECTORY_SEPARATOR . 'b', 'pathName' => File::path($path, 'b', 'b.php'), 'pathName2' => File::path($path, 'b', 'b.php'), 'fileName' => 'b.php'], + ['path' => $path, 'pathName' => File::path($path, 'b'), 'pathName2' => File::path($path, 'b'), 'fileName' => 'b'], + ]; + + $files = []; + foreach (File::enumFile($path) as $file) + { + $files[] = [ + 'path' => $file->getPath(), + 'pathName' => $file->getFullPath(), + 'pathName2' => (string) $file, + 'fileName' => $file->getFileName(), + ]; + } + $this->assertEqualsCanonicalizing($expectedFiles, $files); + + $files = []; + foreach (File::enumFile($path) as $file) + { + $files[] = [ + 'path' => $file->getPath(), + 'pathName' => $file->getFullPath(), + 'pathName2' => (string) $file, + 'fileName' => $file->getFileName(), + ]; + if (is_dir($file->getFullPath())) + { + $file->setContinue(false); + } + } + $this->assertEqualsCanonicalizing([$expectedFiles[0], $expectedFiles[1], $expectedFiles[3], $expectedFiles[6]], $files); + } + + /** + * @testdox enumFileSync + */ + public function testEnumFileSync(): void + { + $result = File::enumFileSync('not file'); + $this->assertFalse($result->getReturn()); + $path = \dirname(__DIR__, 2) . '/Util/File'; $expectedFiles = [ ['pathName' => File::path($path, '1.txt'), 'pathName2' => File::path($path, '1.txt'), 'fileName' => '1.txt'], @@ -134,7 +194,7 @@ public function testEnumFile(): void ]; $files = []; - foreach (File::enumFile($path) as $file) + foreach (File::enumFileSync($path) as $file) { $files[] = [ 'pathName' => $file->getFullPath(), @@ -143,6 +203,15 @@ public function testEnumFile(): void ]; } $this->assertEqualsCanonicalizing($expectedFiles, $files); + + $files = []; + foreach (File::enumFileSync($path, '/1\.txt/') as $file) + { + $files[] = $file->getFullPath(); + } + $this->assertEqualsCanonicalizing([ + File::path($path, '1.txt'), + ], $files); } /** @@ -166,6 +235,7 @@ public function testCreateDir(): void $this->assertDirectoryDoesNotExist($path); $this->assertTrue(File::createDir($path)); $this->assertDirectoryExists($path); + $this->assertFalse(File::createDir('')); } /** @@ -173,15 +243,19 @@ public function testCreateDir(): void */ public function testCrateFile(): void { + $this->assertFalse(File::createFile('')); + $path = Imi::getRuntimePath('test/test.txt'); $this->assertFalse(is_file($path)); $this->assertTrue(File::createFile($path)); $this->assertTrue(is_file($path)); + $this->assertTrue(File::createFile($path)); // 已存在时的测试 $path = Imi::getRuntimePath('test/test/test.txt'); $this->assertFalse(is_file($path)); - $this->assertTrue(File::createFile($path)); + $this->assertTrue(File::createFile($path, '123')); $this->assertTrue(is_file($path)); + $this->assertEquals('123', file_get_contents($path)); } /** @@ -189,6 +263,9 @@ public function testCrateFile(): void */ public function testIsEmptyDir(): void { + $path = Imi::getRuntimePath('test/not found'); + $this->assertTrue(File::isEmptyDir($path)); + $path = Imi::getRuntimePath('test/a/b'); $this->assertTrue(File::isEmptyDir($path)); @@ -201,6 +278,8 @@ public function testIsEmptyDir(): void */ public function testDeleteDir(): void { + mkdir(Imi::getRuntimePath('test/test/a')); + file_put_contents(Imi::getRuntimePath('test/test/a/1.txt'), '123'); $path = Imi::getRuntimePath('test/test'); $this->assertDirectoryExists($path); File::deleteDir($path); @@ -229,15 +308,18 @@ public function testAbsolute(): void if ('\\' === \DIRECTORY_SEPARATOR) { $this->assertEquals('\a\b\c\1.jpg', File::absolute('/a/b/d/e/../../c/./1.jpg')); + $this->assertEquals('phar://\a.phar\b\c\1.jpg', File::absolute('phar:///a.phar/b/d/e/../../c/./1.jpg')); } else { $this->assertEquals('/a/b/c/1.jpg', File::absolute('/a/b/d/e/../../c/./1.jpg')); + $this->assertEquals('phar:///a.phar/b/c/1.jpg', File::absolute('phar:///a.phar/b/d/e/../../c/./1.jpg')); } } public function testGetBaseNameBeforeFirstDot(): void { + $this->assertEquals('', File::getBaseNameBeforeFirstDot('abc')); $this->assertEquals('abc', File::getBaseNameBeforeFirstDot('abc.php')); $this->assertEquals('abc', File::getBaseNameBeforeFirstDot('abc.php.bak')); $this->assertEquals('abc', File::getBaseNameBeforeFirstDot(__DIR__ . \DIRECTORY_SEPARATOR . 'abc.php')); diff --git a/tests/unit/Component/Tests/Util/FilterableListTest.php b/tests/unit/Component/Tests/Util/FilterableListTest.php index 8757b5ed41..bb51251efe 100644 --- a/tests/unit/Component/Tests/Util/FilterableListTest.php +++ b/tests/unit/Component/Tests/Util/FilterableListTest.php @@ -16,11 +16,11 @@ public function testFilterableList(): void { $originData = [ ['id' => 1, 'name' => 'a'], - ['id' => 2, 'name' => 'b'], ]; // 剔除 name 字段 $list = new FilterableList($originData, ['name'], 'deny'); + $list->append($originData[] = ['id' => 2, 'name' => 'b']); foreach ($list as $k => $v) { $this->assertEquals([ @@ -28,6 +28,8 @@ public function testFilterableList(): void ], $v); } + $this->assertEquals(json_encode([['id' => 1], ['id' => 2]]), json_encode($list)); + // 只保留 name 字段 $list = new FilterableList($originData, ['name']); foreach ($list as $k => $v) @@ -40,6 +42,7 @@ public function testFilterableList(): void $this->assertEquals([ 'name' => $originData[0]['name'], ], $list[0]); + $this->assertNull($list[100]); $this->assertEquals([ ['name' => $originData[0]['name']], @@ -47,17 +50,45 @@ public function testFilterableList(): void ], $list->toArray()); $this->assertEquals(2, $list->count()); + $list[] = ['id' => 3, 'name' => 'c']; + $this->assertEquals(3, $list->count()); + $list['test'] = ['id' => 4, 'name' => 'd']; + $this->assertEquals(4, $list->count()); + $this->assertEquals(4, $list->count()); $list->remove($list[0]); - - $this->assertEquals(1, $list->count()); - - $this->assertEquals([ - ['name' => $originData[1]['name']], - ], $list->toArray()); + $this->assertEquals(3, $list->count()); + $this->assertTrue(isset($list['test'])); + unset($list['test']); + $this->assertFalse(isset($list['test'])); + $this->assertEquals(2, $list->count()); $list->clear(); $this->assertEquals(0, $list->count()); } + + public function testFilterableList2(): void + { + $object = new \stdClass(); + $object->id = 1; + + $list = new FilterableList([ + $object, + ['id' => 2], + ], null); + $this->assertEquals(json_encode([ + ['id' => 1], + ['id' => 2], + ]), json_encode($list)); + + $list = new FilterableList([ + $object, + ['id' => 2], + ], [], 'deny'); + $this->assertEquals(json_encode([ + ['id' => 1], + ['id' => 2], + ]), json_encode($list)); + } } diff --git a/tests/unit/Component/Tests/Util/Format/BaseFormatTest.php b/tests/unit/Component/Tests/Util/Format/BaseFormatTest.php new file mode 100644 index 0000000000..7698300ea5 --- /dev/null +++ b/tests/unit/Component/Tests/Util/Format/BaseFormatTest.php @@ -0,0 +1,30 @@ + 'imi', + 'birthday' => '2018-06-21', + ]; + + protected string $class; + + public function test(): void + { + $formatter = new $this->class(); + + $str = $formatter->encode(self::DATA); + $this->assertIsString($str); + $this->assertNotEmpty($str); + + $data = $formatter->decode($str); + $this->assertIsArray($data); + $this->assertEquals(self::DATA, $data); + } +} diff --git a/tests/unit/Component/Tests/Util/Format/JsonTest.php b/tests/unit/Component/Tests/Util/Format/JsonTest.php new file mode 100644 index 0000000000..97846ba267 --- /dev/null +++ b/tests/unit/Component/Tests/Util/Format/JsonTest.php @@ -0,0 +1,12 @@ +assertEquals(MediaType::IMAGE_PNG, MediaType::getContentType('png')); + } +} diff --git a/tests/unit/Component/Tests/Util/Http/Consts/StatusCodeTest.php b/tests/unit/Component/Tests/Util/Http/Consts/StatusCodeTest.php new file mode 100644 index 0000000000..8d9c6b73c0 --- /dev/null +++ b/tests/unit/Component/Tests/Util/Http/Consts/StatusCodeTest.php @@ -0,0 +1,16 @@ +assertEquals('OK', StatusCode::getReasonPhrase(StatusCode::OK)); + } +} diff --git a/tests/unit/Component/Tests/Util/Http/MessageUtilTest.php b/tests/unit/Component/Tests/Util/Http/MessageUtilTest.php new file mode 100644 index 0000000000..80518bd310 --- /dev/null +++ b/tests/unit/Component/Tests/Util/Http/MessageUtilTest.php @@ -0,0 +1,20 @@ +assertEquals([ + 'test' => 'a, b, c', + ], MessageUtil::headersToStringList([ + 'test' => ['a', 'b', 'c'], + ])); + } +} diff --git a/tests/unit/Component/Tests/Util/Http/ResponseTest.php b/tests/unit/Component/Tests/Util/Http/ResponseTest.php new file mode 100644 index 0000000000..8cab80a8c8 --- /dev/null +++ b/tests/unit/Component/Tests/Util/Http/ResponseTest.php @@ -0,0 +1,68 @@ +__testX('with'); + } + + public function testSet(): void + { + $this->__testX('set'); + } + + private function __testX(string $type): void + { + // statusCode + $response = new Response(); + $changeMethod = $type . 'Status'; + $response = $response->{$changeMethod}(StatusCode::NOT_FOUND); + $this->assertEquals(StatusCode::NOT_FOUND, $response->getStatusCode()); + $this->assertEquals(StatusCode::getReasonPhrase(StatusCode::NOT_FOUND), $response->getReasonPhrase()); + + $response = $response->{$changeMethod}(StatusCode::INTERNAL_SERVER_ERROR, 'test'); + $this->assertEquals(StatusCode::INTERNAL_SERVER_ERROR, $response->getStatusCode()); + $this->assertEquals('test', $response->getReasonPhrase()); + + // cookie + $response = new Response(); + $changeMethod = $type . 'Cookie'; + $response = $response->{$changeMethod}('a', '123'); + $this->assertEquals(['a' => [ + 'key' => 'a', + 'value' => '123', + 'expire' => 0, + 'path' => '/', + 'domain' => '', + 'secure' => false, + 'httponly' => false, + ]], $response->getCookieParams()); + $this->assertEquals([ + 'key' => 'a', + 'value' => '123', + 'expire' => 0, + 'path' => '/', + 'domain' => '', + 'secure' => false, + 'httponly' => false, + ], $response->getCookie('a')); + $this->assertEquals('aaa', $response->getCookie('b', 'aaa')); + + // trailer + $response = new Response(); + $changeMethod = $type . 'Trailer'; + $response = $response->{$changeMethod}('a', '123'); + $this->assertEquals(['a' => '123'], $response->getTrailers()); + $this->assertEquals('123', $response->getTrailer('a')); + $this->assertNull($response->getTrailer('b')); + } +} diff --git a/tests/unit/Component/Tests/Util/Http/ServerRequestTest.php b/tests/unit/Component/Tests/Util/Http/ServerRequestTest.php new file mode 100644 index 0000000000..0394bc9be6 --- /dev/null +++ b/tests/unit/Component/Tests/Util/Http/ServerRequestTest.php @@ -0,0 +1,178 @@ + TestServer::class]); + RequestContext::set('server', $server); + Config::addConfig('@server', []); + Config::set('@server.' . __CLASS__, []); + } + + public static function tearDownAfterClass(): void + { + RequestContext::unset('server'); + } + + public function testWith(): void + { + $this->__testX('with'); + } + + public function testSet(): void + { + $this->__testX('set'); + } + + private function __testX(string $type): void + { + $url = 'http://127.0.0.1:8080/test?id=1'; + foreach ([ + 'ProtocolVersion' => '1.1', + 'Body' => new MemoryStream('test'), + 'Method' => RequestMethod::POST, + 'Uri' => new Uri($url), + 'QueryParams' => ['id' => '1'], + 'UploadedFiles' => [ + new UploadedFile('1.jpg', MediaType::IMAGE_JPEG, '/tmp/1.jpg', 1024, 0), + ], + 'ParsedBody' => ['name' => 'imi'], + ] as $name => $value) + { + $request = new ServerRequest(); + $changeMethod = $type . $name; + $getMethod = 'get' . $name; + $request = $request->{$changeMethod}($value); + $this->assertEquals($value, $request->{$getMethod}(), 'Test ' . $type . $name); + } + + $request = new ServerRequest(); + $this->assertNull($request->getUri()); + + $this->__testHeader($type); + $this->__testParsedBody($type); + + // requestTarget + $request = new ServerRequest(); + $request->setUri(new Uri($url)); + $this->assertEquals('/test?id=1', $request->getRequestTarget()); + $changeMethod = $type . 'RequestTarget'; + $request = $request->{$changeMethod}('/test'); + $this->assertEquals('/test', $request->getRequestTarget(), 'Test ' . $type . 'RequestTarget'); + + // serverParams + $request = new ServerRequest(); + $this->assertEquals([], $request->getServerParams()); + $this->assertEquals(1, $request->getServerParam('test', 1)); + + // cookie + $request = new ServerRequest(); + $changeMethod = $type . 'CookieParams'; + $request = $request->{$changeMethod}(['a' => '123']); + $this->assertEquals(['a' => '123'], $request->getCookieParams()); + $this->assertEquals('123', $request->getCookie('a')); + $this->assertEquals('aaa', $request->getCookie('b', 'aaa')); + + // attribute + $request = new ServerRequest(); + $changeMethod = $type . 'Attribute'; + $request = $request->{$changeMethod}('a', '123'); + $this->assertEquals('123', $request->getAttribute('a')); + $this->assertEquals('aaa', $request->getAttribute('b', 'aaa')); + $this->assertEquals(['a' => '123'], $request->getAttributes()); + $changeMethod = 'with' === $type ? 'withoutAttribute' : 'removeAttribute'; + $request = $request->{$changeMethod}('a'); + $this->assertEquals([], $request->getAttributes()); + } + + private function __testHeader(string $type): void + { + // withHeader/setHeader + $request = new ServerRequest(); + $changeMethod = $type . 'Header'; + // 改变 2 次 + $this->assertFalse($request->hasHeader('name')); + $request = $request->{$changeMethod}('name', 'php'); + $request = $request->{$changeMethod}('name', 'imi'); + $this->assertTrue($request->hasHeader('name')); + $this->assertEquals('imi', $request->getHeaderLine('name')); + $this->assertEquals(['imi'], $request->getHeader('name')); + $this->assertEquals(['name' => ['imi']], $request->getHeaders()); + + // withAddedHeader/addHeader + $request = new ServerRequest(); + $changeMethod = 'with' === $type ? 'withAddedHeader' : 'addHeader'; + // 增加 2 次 + $this->assertFalse($request->hasHeader('imi')); + $request = $request->{$changeMethod}('imi', 'niubi'); + $request = $request->{$changeMethod}('imi', 'test'); + $this->assertTrue($request->hasHeader('imi')); + $this->assertEquals('niubi,test', $request->getHeaderLine('imi')); + $this->assertEquals(['niubi', 'test'], $request->getHeader('imi')); + $this->assertEquals(['imi' => ['niubi', 'test']], $request->getHeaders()); + + // withoutHeader/removeHeader + $changeMethod = 'with' === $type ? 'withoutHeader' : 'removeHeader'; + $this->assertTrue($request->hasHeader('imi')); + $request = $request->{$changeMethod}('imi'); + $this->assertFalse($request->hasHeader('imi')); + } + + private function __testParsedBody(string $type): void + { + $request = new ServerRequest(); + $changeMethod = $type . 'ParsedBody'; + $request = $request->{$changeMethod}(['name' => 'imi']); + $this->assertEquals(['name' => 'imi'], $request->getParsedBody()); + + // json array + Config::set('@server.' . __CLASS__ . '.jsonBodyIsObject', false); + $request = new ServerRequest(); + $request->setBody(new MemoryStream(json_encode(['name' => 'imi']))) + ->setHeader(RequestHeader::CONTENT_TYPE, MediaType::APPLICATION_JSON); + $this->assertEquals(['name' => 'imi'], $request->getParsedBody()); + $this->assertEquals($request->getParsedBody(), $request->post()); + + // json object + Config::set('@server.' . __CLASS__ . '.jsonBodyIsObject', true); + $request = new ServerRequest(); + $request->setBody(new MemoryStream(json_encode(['name' => 'imi']))) + ->setHeader(RequestHeader::CONTENT_TYPE, MediaType::APPLICATION_JSON); + $parsedBody = $request->getParsedBody(); + $this->assertInstanceOf(\stdClass::class, $parsedBody); + $this->assertEquals('imi', $parsedBody->name ?? null); + $this->assertEquals($request->getParsedBody(), $request->post()); + + // xml + $xml = <<<'XML' + + imi + + XML; + $request = new ServerRequest(); + $request->setBody(new MemoryStream($xml)) + ->setHeader(RequestHeader::CONTENT_TYPE, MediaType::APPLICATION_XML); + /** @var \DOMDocument $parsedBody */ + $parsedBody = $request->getParsedBody(); + $this->assertInstanceOf(\DOMDocument::class, $parsedBody); + $this->assertEquals($xml, $parsedBody->saveXML()); + } +} diff --git a/tests/unit/Component/Tests/Util/ImiTest.php b/tests/unit/Component/Tests/Util/ImiTest.php index 333f22b8f9..1f4ecfeb12 100644 --- a/tests/unit/Component/Tests/Util/ImiTest.php +++ b/tests/unit/Component/Tests/Util/ImiTest.php @@ -4,10 +4,12 @@ namespace Imi\Test\Component\Tests\Util; +use Imi\App; use Imi\Test\BaseTest; use Imi\Test\Component\Util\Imi\TestPropertyClass; use Imi\Util\File; use Imi\Util\Imi; +use Imi\Util\Process\ProcessAppContexts; /** * @testdox Imi\Util\Imi @@ -139,20 +141,32 @@ public function testCheckCompareRules(): void */ public function testCheckCompareRule(): void { - $this->assertTrue(Imi::checkCompareRule('a=1', static function (string $name) { + $this->assertTrue(Imi::checkCompareRule('a=1', function (string $name) { static $data = [ 'a' => 1, ]; + $this->assertEquals('a', $name); return $data[$name]; })); - $this->assertFalse(Imi::checkCompareRule('a=2', static function (string $name) { + $this->assertFalse(Imi::checkCompareRule('a=2', function (string $name) { static $data = [ 'a' => 1, ]; + $this->assertEquals('a', $name); return $data[$name]; })); + $this->assertTrue(Imi::checkCompareRule('!id', function (string $name) { + $this->assertEquals('id', $name); + + return null; + })); + $this->assertTrue(Imi::checkCompareRule('test', function (string $name) { + $this->assertEquals('test', $name); + + return true; + })); } /** @@ -229,6 +243,7 @@ public function testGetNamespacePath(): void { $this->assertEquals(__DIR__, Imi::getNamespacePath('Imi\Test\Component\Tests\Util')); $this->assertEquals(__DIR__, Imi::getNamespacePath('Imi\Test\Component\Tests\Util', true)); + $this->assertNull(Imi::getNamespacePath('Imi\Test\Unused\Test')); } /** @@ -252,4 +267,74 @@ public function testGetClassPropertyValue(): void $this->assertEquals(1, Imi::getClassPropertyValue(TestPropertyClass::class, 'a')); $this->assertEquals('bbb', Imi::getClassPropertyValue(TestPropertyClass::class, 'b')); } + + public function testGetImiCmd(): void + { + $cmd = '"' . \PHP_BINARY . '" ' . escapeshellarg(App::get(ProcessAppContexts::SCRIPT_NAME) ?? realpath($_SERVER['SCRIPT_FILENAME'])) . ' ' . escapeshellarg('test'); + $namespace = ' --app-namespace ' . escapeshellarg(App::getNamespace()); + $this->assertEquals($cmd . $namespace, Imi::getImiCmd('test')); + + $this->assertEquals($cmd . ' ' . escapeshellarg('arguments') . ' -a -b ' . escapeshellarg('bbb') . ' --cc --dd ' . escapeshellarg('ddd') . $namespace, Imi::getImiCmd('test', ['arguments'], ['a', 'b' => 'bbb', 'cc', 'dd' => 'ddd'])); + } + + public function testGetImiCmdArray(): void + { + $cmdTpl = [ + \PHP_BINARY, + App::get(ProcessAppContexts::SCRIPT_NAME) ?? realpath($_SERVER['SCRIPT_FILENAME']), + 'test', + ]; + $cmd = $cmdTpl; + $cmd[] = '--app-namespace'; + $cmd[] = App::getNamespace(); + $this->assertEquals($cmd, Imi::getImiCmdArray('test')); + + $cmd = $cmdTpl; + $cmd[] = 'arguments'; + $cmd[] = '-a'; + $cmd[] = '-b'; + $cmd[] = 'bbb'; + $cmd[] = '--cc'; + $cmd[] = '--dd'; + $cmd[] = 'ddd'; + $cmd[] = '--app-namespace'; + $cmd[] = App::getNamespace(); + $this->assertEquals($cmd, Imi::getImiCmdArray('test', ['arguments'], ['a', 'b' => 'bbb', 'cc', 'dd' => 'ddd'])); + } + + public function testGetModeRuntimePath(): void + { + $this->assertEquals(\dirname(__DIR__, 2) . \DIRECTORY_SEPARATOR . '.runtime' . \DIRECTORY_SEPARATOR . 'test' . \DIRECTORY_SEPARATOR . 'a', Imi::getModeRuntimePath('test', 'a')); + } + + public function testGetCurrentModeRuntimePath(): void + { + $this->assertEquals(\dirname(__DIR__, 2) . \DIRECTORY_SEPARATOR . '.runtime' . \DIRECTORY_SEPARATOR . 'cli' . \DIRECTORY_SEPARATOR . 'a', Imi::getCurrentModeRuntimePath('a')); + } + + public function testEval(): void + { + $this->assertEquals(3, Imi::eval('return 1+2;')); + $this->assertEquals(4, Imi::eval('return 2+2;', null, false)); + } + + public function testCheckAppType(): void + { + $this->assertTrue(Imi::checkAppType('cli')); + $this->assertFalse(Imi::checkAppType('swoole')); + } + + public function testFormatByte(): void + { + $this->assertEquals('1.00 B', Imi::formatByte(1)); + $this->assertEquals('1.00 KB', Imi::formatByte(1024)); + $this->assertEquals('1.00 MB', Imi::formatByte(1024 * 1024)); + $this->assertEquals('1.00 GB', Imi::formatByte(1024 * 1024 * 1024)); + $this->assertEquals('1.00 TB', Imi::formatByte(1024 * 1024 * 1024 * 1024)); + $this->assertEquals('1.00 PB', Imi::formatByte(1024 * 1024 * 1024 * 1024 * 1024)); + $this->assertEquals('1024.00 PB', Imi::formatByte(1024 * 1024 * 1024 * 1024 * 1024 * 1024)); + + $this->assertEquals('1.006 KB', Imi::formatByte(1030, 3)); + $this->assertEquals('1.006', Imi::formatByte(1030, 3, false)); + } } diff --git a/tests/unit/Component/Tests/Util/ObjectArrayHelperTest.php b/tests/unit/Component/Tests/Util/ObjectArrayHelperTest.php index 1356d4936a..6f35af8f76 100644 --- a/tests/unit/Component/Tests/Util/ObjectArrayHelperTest.php +++ b/tests/unit/Component/Tests/Util/ObjectArrayHelperTest.php @@ -17,6 +17,8 @@ private function getTestData(): array $data2 = new \stdClass(); $data2->id = 2; $data2->name = 'b'; + $data2->object = new \stdClass(); + $data2->object->value = 123; return [ 'name' => 'imi', @@ -35,13 +37,22 @@ public function testGetAndSet(): void $data = $this->getTestData(); $this->assertEquals($data['data1']['name'], ObjectArrayHelper::get($data, 'data1.name')); + ObjectArrayHelper::set($data, '', ''); + ObjectArrayHelper::set($data, 'data2.name', $data['data2']->name . '-2'); $this->assertEquals('b-2', $data['data2']->name); $this->assertEquals($data['data2']->name, ObjectArrayHelper::get($data, 'data2.name')); + $this->assertEquals(123, ObjectArrayHelper::get($data, 'data2.object.value')); + ObjectArrayHelper::set($data, 'data2.object.value', 456); + $this->assertEquals(456, ObjectArrayHelper::get($data, 'data2.object.value')); + ObjectArrayHelper::set($data, 'description', 'imi niubi'); $this->assertEquals('imi niubi', $data['description']); $this->assertEquals($data['description'], ObjectArrayHelper::get($data, 'description')); + + $this->assertEquals(123, ObjectArrayHelper::get($data, 'data1.id.a', 123)); + $this->assertEquals(456, ObjectArrayHelper::get($data, '', 456)); } public function testExists(): void @@ -61,6 +72,9 @@ public function testRemove(): void $this->assertTrue(ObjectArrayHelper::exists($data, 'name')); $this->assertTrue(ObjectArrayHelper::exists($data, 'data1.name')); $this->assertTrue(ObjectArrayHelper::exists($data, 'data2.name')); + $this->assertTrue(ObjectArrayHelper::exists($data, 'data2.object.value')); + + ObjectArrayHelper::remove($data, ''); ObjectArrayHelper::remove($data, 'name'); $this->assertFalse(ObjectArrayHelper::exists($data, 'name')); @@ -68,6 +82,8 @@ public function testRemove(): void $this->assertFalse(ObjectArrayHelper::exists($data, 'data1.name')); ObjectArrayHelper::remove($data, 'data2.name'); $this->assertFalse(ObjectArrayHelper::exists($data, 'data2.name')); + ObjectArrayHelper::remove($data, 'data2.object.value'); + $this->assertFalse(ObjectArrayHelper::exists($data, 'data2.object.value')); } public function testColumn(): void @@ -131,5 +147,27 @@ public function testFilter(): void ObjectArrayHelper::filter($data, ['name'], 'deny'); $this->assertEquals(1, $data->id); $this->assertFalse(ObjectArrayHelper::exists($data, 'name')); + + $this->expectExceptionMessage('Unknow mode abc'); + ObjectArrayHelper::filter($data, ['name'], 'abc'); + } + + public function testToArray(): void + { + $data = new \ArrayObject(['name' => 'imi']); + $this->assertEquals([ + 'name' => 'imi', + ], ObjectArrayHelper::toArray($data)); + + $data = (static fn () => yield 'name' => 'imi')(); + $this->assertEquals([ + 'name' => 'imi', + ], ObjectArrayHelper::toArray($data)); + + $data = new \stdClass(); + $data->name = 'imi'; + $this->assertEquals([ + 'name' => 'imi', + ], ObjectArrayHelper::toArray($data)); } } diff --git a/tests/unit/Component/Tests/Util/Socket/IPEndPointTest.php b/tests/unit/Component/Tests/Util/Socket/IPEndPointTest.php new file mode 100644 index 0000000000..bee66798b8 --- /dev/null +++ b/tests/unit/Component/Tests/Util/Socket/IPEndPointTest.php @@ -0,0 +1,19 @@ +assertEquals('127.0.0.1', $point->getAddress()); + $this->assertEquals(80, $point->getPort()); + $this->assertEquals('127.0.0.1:80', (string) $point); + } +} diff --git a/tests/unit/Component/Tests/Util/Stream/BaseStreamTest.php b/tests/unit/Component/Tests/Util/Stream/BaseStreamTest.php new file mode 100644 index 0000000000..cf34fe13ae --- /dev/null +++ b/tests/unit/Component/Tests/Util/Stream/BaseStreamTest.php @@ -0,0 +1,93 @@ +newStream(); + $this->assertEquals($this->seekable, $stream->isSeekable()); + $this->assertEquals($this->writable, $stream->isWritable()); + $this->assertEquals($this->readable, $stream->isReadable()); + $this->assertEquals(\strlen($this->initContent), $stream->getSize()); + $this->assertEquals(0, $stream->tell()); + if (!$this->readable) + { + return; + } + + // initContent + $stream = $this->newStream(); + $this->assertEquals($this->initContent, (string) $stream); + if ($this->seekable) + { + $stream->seek(0); + } + else + { + $stream = $this->newStream(); + } + $this->assertEquals($this->initContent, $stream->getContents()); + + // writeContent + if ($this->writable) + { + $this->assertEquals(\strlen($this->writeContent), $stream->write($this->writeContent)); + } + $this->assertTrue($stream->eof()); + if ($this->seekable) + { + $stream->seek(-1, \SEEK_END); + $this->assertEquals(substr($this->writeContent, -1), $stream->read(1)); + + $stream->seek(-\strlen($this->writeContent), \SEEK_END); + $this->assertEquals($this->writeContent, $stream->getContents()); + + $stream->rewind(); + $this->assertEquals(0, $stream->tell()); + $this->assertEquals($this->initContent . $this->writeContent, $stream->getContents()); + } + if ($this->writable && $this->readable) + { + // 开头写入 + $stream->seek(0); + $stream->write('a'); + $stream->seek(0); + $this->assertEquals('a', $stream->read(1)); + + // 中间写入 + $stream->seek(3, \SEEK_CUR); + $stream->write('c'); + $stream->seek(-1, \SEEK_CUR); + $this->assertEquals('c', $stream->read(1)); + + // 结束写入 + $stream->seek(0, \SEEK_END); + $stream->write('b'); + $stream->seek(-1, \SEEK_END); + $this->assertEquals('b', $stream->read(1)); + } + + // close + $stream = $this->newStream(); + $stream->close(); + } + + abstract protected function newStream(): StreamInterface; +} diff --git a/tests/unit/Component/Tests/Util/Stream/FileStreamStreamTest.php b/tests/unit/Component/Tests/Util/Stream/FileStreamStreamTest.php new file mode 100644 index 0000000000..b6521b1bfe --- /dev/null +++ b/tests/unit/Component/Tests/Util/Stream/FileStreamStreamTest.php @@ -0,0 +1,19 @@ +getUrl(), StreamMode::READ_WRITE_CLEAN); + + return new FileStream($fp, StreamMode::READ_WRITE_CLEAN); + } +} diff --git a/tests/unit/Component/Tests/Util/Stream/FileStreamTest.php b/tests/unit/Component/Tests/Util/Stream/FileStreamTest.php new file mode 100644 index 0000000000..3908e3ee9d --- /dev/null +++ b/tests/unit/Component/Tests/Util/Stream/FileStreamTest.php @@ -0,0 +1,36 @@ +newStream(); + $this->assertIsArray($stream->getMetadata()); + $this->assertIsResource($stream->detach()); + $this->assertEquals($this->getUrl(), (string) $stream->getUri()); + } + + protected function getUrl(): string + { + return 'file://' . ('Windows' === \PHP_OS_FAMILY ? '/' : '') . \dirname(__DIR__, 3) . '/.runtime/test.txt'; + } + + /** + * @return FileStream + */ + protected function newStream(): StreamInterface + { + return new FileStream($this->getUrl(), StreamMode::READ_WRITE_CLEAN); + } +} diff --git a/tests/unit/Component/Tests/Util/Stream/FileStreamUriTest.php b/tests/unit/Component/Tests/Util/Stream/FileStreamUriTest.php new file mode 100644 index 0000000000..718d25bd9b --- /dev/null +++ b/tests/unit/Component/Tests/Util/Stream/FileStreamUriTest.php @@ -0,0 +1,18 @@ +getUrl()), StreamMode::READ_WRITE_CLEAN); + } +} diff --git a/tests/unit/Component/Tests/Util/Stream/MemoryStreamTest.php b/tests/unit/Component/Tests/Util/Stream/MemoryStreamTest.php new file mode 100644 index 0000000000..5a24b1940c --- /dev/null +++ b/tests/unit/Component/Tests/Util/Stream/MemoryStreamTest.php @@ -0,0 +1,24 @@ +newStream(); + $this->assertNull($stream->getMetadata()); + $this->assertNull($stream->detach()); + } + + protected function newStream(): StreamInterface + { + return new MemoryStream($this->initContent); + } +} diff --git a/tests/unit/Component/Tests/Util/TextTest.php b/tests/unit/Component/Tests/Util/TextTest.php index 51e0302e7c..9cf0de7726 100644 --- a/tests/unit/Component/Tests/Util/TextTest.php +++ b/tests/unit/Component/Tests/Util/TextTest.php @@ -21,6 +21,7 @@ public function testStartwith(): void $this->assertFalse(Text::startwith('imi is very niu bi', 'niu bi')); $this->assertFalse(Text::startwith('imi is very niu bi', 'Imi')); $this->assertFalse(Text::startwith('imi is very niu bi', 'Imi', true)); + $this->assertTrue(Text::startwith('imi is very niu bi', 'Imi', false)); } /** @@ -32,6 +33,7 @@ public function testEndwith(): void $this->assertFalse(Text::endwith('imi is very niu bi', 'imi')); $this->assertFalse(Text::endwith('imi is very niu bi', 'Niu BI')); $this->assertFalse(Text::endwith('imi is very niu bi', 'Niu BI', true)); + $this->assertFalse(Text::endwith('imi is very niu bi', 'Niu BI', false)); } /** diff --git a/tests/unit/Component/Tests/Util/UriTest.php b/tests/unit/Component/Tests/Util/UriTest.php index a13e915418..5b46e49275 100644 --- a/tests/unit/Component/Tests/Util/UriTest.php +++ b/tests/unit/Component/Tests/Util/UriTest.php @@ -12,9 +12,6 @@ */ class UriTest extends BaseTest { - /** - * @testdox startwith - */ public function testUri(): void { $url = 'https://admin:123456@www.baidu.com/a/b/c.jpg?id=1&name=imi#gg'; @@ -37,6 +34,10 @@ public function testUri(): void $this->assertEquals('http', $uri->getScheme()); $this->assertEquals('www.imiphp.com:4433', $uri->getAuthority()); $this->assertEquals('', $uri->getUserInfo()); + $uri2 = $uri->withUserInfo('yurun'); + $this->assertEquals('yurun', $uri2->getUserInfo()); + $uri2 = $uri->withUserInfo('yurun', '123456'); + $this->assertEquals('yurun:123456', $uri2->getUserInfo()); $this->assertEquals('www.imiphp.com', $uri->getHost()); $this->assertEquals(4433, $uri->getPort()); $this->assertEquals(4433, Uri::getServerPort($uri)); @@ -60,5 +61,20 @@ public function testUri(): void $url, Uri::makeUriString($uri->getHost(), $uri->getPath(), $uri->getQuery(), $uri->getPort(), $uri->getScheme(), $uri->getFragment(), $uri->getUserInfo()) ); + + $uri = Uri::makeUri('127.0.0.1', '/imi', 'id=1', 80, 'http', 'gg', 'admin:123456'); + $this->assertEquals('127.0.0.1', $uri->getHost()); + $this->assertEquals('/imi', $uri->getPath()); + $this->assertEquals('id=1', $uri->getQuery()); + $this->assertEquals(80, $uri->getPort()); + $this->assertEquals('http', $uri->getScheme()); + $this->assertEquals('gg', $uri->getFragment()); + $this->assertEquals('admin:123456', $uri->getUserInfo()); + } + + public function testInvalidUri(): void + { + $this->expectExceptionMessageMatches('/Uri .+ parse error/'); + new Uri('http:////www.baidu.com'); } } diff --git a/tests/unit/Component/Util/ClassObject/Test.php b/tests/unit/Component/Util/ClassObject/Test.php index 9e95d2e767..e7bda65b8b 100644 --- a/tests/unit/Component/Util/ClassObject/Test.php +++ b/tests/unit/Component/Util/ClassObject/Test.php @@ -41,4 +41,12 @@ public function __construct($a, $b, $c = 'imi.com') public function imi($a, $b, $c = 'imi.com'): void { } + + public function noParam(): void + { + } + + public function variadic(string ...$params): void + { + } } diff --git a/tests/unit/Component/Util/ClassObject/TestNoConstrauct.php b/tests/unit/Component/Util/ClassObject/TestNoConstrauct.php new file mode 100644 index 0000000000..022ea705c2 --- /dev/null +++ b/tests/unit/Component/Util/ClassObject/TestNoConstrauct.php @@ -0,0 +1,9 @@ +