From 5220b2227dec156aa4a4406bb26b5b7e012d2d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 15:35:40 +0800 Subject: [PATCH 001/225] Deleted useless code. --- src/http-server/src/ConfigProvider.php | 1 - src/http-server/src/Server.php | 32 +++++++++++++------------- src/http-server/src/ServerFactory.php | 26 --------------------- src/json-rpc/src/ConfigProvider.php | 1 - src/json-rpc/src/HttpServer.php | 16 +++++-------- src/json-rpc/src/HttpServerFactory.php | 29 ----------------------- src/testing/src/Client.php | 4 +--- 7 files changed, 23 insertions(+), 86 deletions(-) delete mode 100644 src/http-server/src/ServerFactory.php delete mode 100644 src/json-rpc/src/HttpServerFactory.php diff --git a/src/http-server/src/ConfigProvider.php b/src/http-server/src/ConfigProvider.php index ce42420de..2bd8340bb 100644 --- a/src/http-server/src/ConfigProvider.php +++ b/src/http-server/src/ConfigProvider.php @@ -22,7 +22,6 @@ class ConfigProvider { return [ 'dependencies' => [ - Server::class => ServerFactory::class, RequestInterface::class => Request::class, ServerRequestInterface::class => Request::class, ResponseInterface::class => Response::class, diff --git a/src/http-server/src/Server.php b/src/http-server/src/Server.php index bedfe9de1..4992a6e93 100644 --- a/src/http-server/src/Server.php +++ b/src/http-server/src/Server.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Hyperf\HttpServer; +use FastRoute\Dispatcher; use Hyperf\Contract\ConfigInterface; use Hyperf\Contract\MiddlewareInitializerInterface; use Hyperf\Contract\OnRequestInterface; @@ -20,6 +21,7 @@ use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler; +use Hyperf\HttpServer\Router\DispatcherFactory; use Hyperf\Utils\Context; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; @@ -36,11 +38,6 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface */ protected $middlewares; - /** - * @var string - */ - protected $coreHandler; - /** * @var MiddlewareInterface */ @@ -66,16 +63,10 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface */ protected $serverName; - public function __construct( - string $serverName, - string $coreHandler, - ContainerInterface $container, - $dispatcher - ) { - $this->serverName = $serverName; - $this->coreHandler = $coreHandler; + public function __construct(ContainerInterface $container) + { $this->container = $container; - $this->dispatcher = $dispatcher; + $this->dispatcher = $container->get(HttpDispatcher::class); } public function initCoreMiddleware(string $serverName): void @@ -123,6 +114,16 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface return $this; } + protected function createDispatcher(string $serverName): Dispatcher + { + $factory = $this->container->get(DispatcherFactory::class); + return $factory->getDispatcher($serverName); + } + + protected function parse(): array + { + } + protected function getDefaultExceptionHandler(): array { return [ @@ -132,8 +133,7 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface protected function createCoreMiddleware(): MiddlewareInterface { - $coreHandler = $this->coreHandler; - return new $coreHandler($this->container, $this->serverName); + return new CoreMiddleware($this->container, $this->serverName); } protected function initRequestAndResponse(SwooleRequest $request, SwooleResponse $response): array diff --git a/src/http-server/src/ServerFactory.php b/src/http-server/src/ServerFactory.php deleted file mode 100644 index bc4226735..000000000 --- a/src/http-server/src/ServerFactory.php +++ /dev/null @@ -1,26 +0,0 @@ -coreMiddleware, $container, $container->get(HttpDispatcher::class)); - } -} diff --git a/src/json-rpc/src/ConfigProvider.php b/src/json-rpc/src/ConfigProvider.php index 20df9878d..e1a5bb000 100644 --- a/src/json-rpc/src/ConfigProvider.php +++ b/src/json-rpc/src/ConfigProvider.php @@ -23,7 +23,6 @@ class ConfigProvider return [ 'dependencies' => [ TcpServer::class => TcpServerFactory::class, - HttpServer::class => HttpServerFactory::class, DataFormatter::class => DataFormatterFactory::class, ], 'commands' => [ diff --git a/src/json-rpc/src/HttpServer.php b/src/json-rpc/src/HttpServer.php index ff8dcf0bf..bc57545b7 100644 --- a/src/json-rpc/src/HttpServer.php +++ b/src/json-rpc/src/HttpServer.php @@ -18,6 +18,7 @@ use Hyperf\HttpServer\Server; use Hyperf\JsonRpc\Exception\Handler\HttpExceptionHandler; use Hyperf\Rpc\Protocol; use Hyperf\Rpc\ProtocolManager; +use Hyperf\RpcServer\RequestDispatcher; use Hyperf\Utils\Context; use Psr\Container\ContainerInterface; use Psr\Http\Message\RequestInterface; @@ -44,14 +45,10 @@ class HttpServer extends Server */ protected $responseBuilder; - public function __construct( - string $serverName, - string $coreHandler, - ContainerInterface $container, - $dispatcher, - ProtocolManager $protocolManager - ) { - parent::__construct($serverName, $coreHandler, $container, $dispatcher); + public function __construct(ContainerInterface $container, ProtocolManager $protocolManager) + { + $this->container = $container; + $this->dispatcher = $container->get(RequestDispatcher::class); $this->protocol = new Protocol($container, $protocolManager, 'jsonrpc-http'); $this->packer = $this->protocol->getPacker(); $this->responseBuilder = make(ResponseBuilder::class, [ @@ -69,8 +66,7 @@ class HttpServer extends Server protected function createCoreMiddleware(): MiddlewareInterface { - $coreHandler = $this->coreHandler; - return new $coreHandler($this->container, $this->protocol, $this->serverName); + return new HttpCoreMiddleware($this->container, $this->protocol, $this->serverName); } protected function initRequestAndResponse(SwooleRequest $request, SwooleResponse $response): array diff --git a/src/json-rpc/src/HttpServerFactory.php b/src/json-rpc/src/HttpServerFactory.php deleted file mode 100644 index 5844bad02..000000000 --- a/src/json-rpc/src/HttpServerFactory.php +++ /dev/null @@ -1,29 +0,0 @@ -get(RequestDispatcher::class); - $protocolManager = $container->get(ProtocolManager::class); - return new HttpServer('jsonrpc-http', $this->coreMiddleware, $container, $dispatcher, $protocolManager); - } -} diff --git a/src/testing/src/Client.php b/src/testing/src/Client.php index cc333e085..b5cc086d8 100644 --- a/src/testing/src/Client.php +++ b/src/testing/src/Client.php @@ -13,13 +13,11 @@ declare(strict_types=1); namespace Hyperf\Testing; use Hyperf\Contract\PackerInterface; -use Hyperf\Dispatcher\HttpDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\HttpMessage\Upload\UploadedFile; use Hyperf\HttpMessage\Uri\Uri; -use Hyperf\HttpServer\CoreMiddleware; use Hyperf\HttpServer\MiddlewareManager; use Hyperf\HttpServer\Server; use Hyperf\Utils\Arr; @@ -49,7 +47,7 @@ class Client extends Server public function __construct(ContainerInterface $container, PackerInterface $packer = null, $server = 'http') { - parent::__construct('http', CoreMiddleware::class, $container, $container->get(HttpDispatcher::class)); + parent::__construct($container); $this->packer = $packer ?? new JsonPacker(); $this->initCoreMiddleware($server); From 0ff9cdfa5b214a701893218e72b06a0cfc26d064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 15:45:44 +0800 Subject: [PATCH 002/225] Update Server.php --- src/http-server/src/Server.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/http-server/src/Server.php b/src/http-server/src/Server.php index 4992a6e93..c4cbd2f76 100644 --- a/src/http-server/src/Server.php +++ b/src/http-server/src/Server.php @@ -58,6 +58,11 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface */ protected $dispatcher; + /** + * @var Dispatcher + */ + protected $routerDispatcher; + /** * @var string */ @@ -73,6 +78,7 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface { $this->serverName = $serverName; $this->coreMiddleware = $this->createCoreMiddleware(); + $this->routerDispatcher = $this->createDispatcher($serverName); $config = $this->container->get(ConfigInterface::class); $this->middlewares = $config->get('middlewares.' . $serverName, []); @@ -84,6 +90,8 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface try { [$psr7Request, $psr7Response] = $this->initRequestAndResponse($request, $response); + $psr7Request = $this->parse($psr7Request); + $middlewares = array_merge($this->middlewares, MiddlewareManager::get($this->serverName, $psr7Request->getUri()->getPath(), $psr7Request->getMethod())); $psr7Response = $this->dispatcher->dispatch($psr7Request, $middlewares, $this->coreMiddleware); @@ -120,8 +128,13 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface return $factory->getDispatcher($serverName); } - protected function parse(): array + protected function parse(ServerRequestInterface $request): ServerRequestInterface { + $uri = $request->getUri(); + + $routes = $this->routerDispatcher->dispatch($request->getMethod(), $uri->getPath()); + + return $request->withAttribute('routes', $routes); } protected function getDefaultExceptionHandler(): array From 62f8fa4eeacfce36f4cce68903ebdfd03913c3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 15:48:12 +0800 Subject: [PATCH 003/225] Update branch-alias to 1.1-dev. --- bin/release.sh | 2 +- bin/split.sh | 2 +- src/amqp/composer.json | 2 +- src/async-queue/composer.json | 2 +- src/cache/composer.json | 2 +- src/circuit-breaker/composer.json | 2 +- src/command/composer.json | 2 +- src/config-aliyun-acm/composer.json | 2 +- src/config-apollo/composer.json | 2 +- src/config-etcd/composer.json | 2 +- src/config/composer.json | 2 +- src/constants/composer.json | 2 +- src/consul/composer.json | 2 +- src/contract/composer.json | 2 +- src/crontab/composer.json | 2 +- src/database/composer.json | 2 +- src/db-connection/composer.json | 2 +- src/devtool/composer.json | 2 +- src/di/composer.json | 2 +- src/dispatcher/composer.json | 2 +- src/elasticsearch/composer.json | 2 +- src/etcd/composer.json | 2 +- src/event/composer.json | 2 +- src/exception-handler/composer.json | 2 +- src/framework/composer.json | 2 +- src/graphql/composer.json | 2 +- src/grpc-client/composer.json | 2 +- src/grpc-server/composer.json | 2 +- src/grpc/composer.json | 2 +- src/guzzle/composer.json | 2 +- src/http-message/composer.json | 2 +- src/http-server/composer.json | 2 +- src/json-rpc/composer.json | 2 +- src/load-balancer/composer.json | 2 +- src/logger/composer.json | 2 +- src/memory/composer.json | 2 +- src/model-cache/composer.json | 2 +- src/paginator/composer.json | 2 +- src/pool/composer.json | 2 +- src/process/composer.json | 2 +- src/rate-limit/composer.json | 2 +- src/redis/composer.json | 2 +- src/rpc-client/composer.json | 2 +- src/rpc-server/composer.json | 2 +- src/rpc/composer.json | 2 +- src/server/composer.json | 2 +- src/service-governance/composer.json | 2 +- src/swagger/composer.json | 2 +- src/swoole-enterprise/composer.json | 2 +- src/task/composer.json | 2 +- src/testing/composer.json | 2 +- src/tracer/composer.json | 2 +- src/utils/composer.json | 2 +- src/view/composer.json | 2 +- src/websocket-client/composer.json | 2 +- src/websocket-server/composer.json | 2 +- 56 files changed, 56 insertions(+), 56 deletions(-) diff --git a/bin/release.sh b/bin/release.sh index 1c7cf2d09..cf169feed 100755 --- a/bin/release.sh +++ b/bin/release.sh @@ -9,7 +9,7 @@ then fi NOW=$(date +%s) -CURRENT_BRANCH="master" +CURRENT_BRANCH="1.1" VERSION=$1 BASEPATH=$(cd `dirname $0`; cd ../src/; pwd) diff --git a/bin/split.sh b/bin/split.sh index 68cbc71b1..fbfa0de9b 100755 --- a/bin/split.sh +++ b/bin/split.sh @@ -3,7 +3,7 @@ set -e set -x -CURRENT_BRANCH="master" +CURRENT_BRANCH="1.1" BASEPATH=$(cd `dirname $0`; cd ../src/; pwd) REPOS=$@ diff --git a/src/amqp/composer.json b/src/amqp/composer.json index e6a258e79..ac3b7cb96 100644 --- a/src/amqp/composer.json +++ b/src/amqp/composer.json @@ -49,7 +49,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Amqp\\ConfigProvider" diff --git a/src/async-queue/composer.json b/src/async-queue/composer.json index c2acd9bb9..8c3f928a7 100644 --- a/src/async-queue/composer.json +++ b/src/async-queue/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\AsyncQueue\\ConfigProvider" diff --git a/src/cache/composer.json b/src/cache/composer.json index 44a3d8852..4aae816c9 100644 --- a/src/cache/composer.json +++ b/src/cache/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Cache\\ConfigProvider" diff --git a/src/circuit-breaker/composer.json b/src/circuit-breaker/composer.json index 6d3b3bdee..e9142061e 100644 --- a/src/circuit-breaker/composer.json +++ b/src/circuit-breaker/composer.json @@ -40,7 +40,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\CircuitBreaker\\ConfigProvider" diff --git a/src/command/composer.json b/src/command/composer.json index d4dca7fc3..7596550fe 100644 --- a/src/command/composer.json +++ b/src/command/composer.json @@ -33,7 +33,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" } }, "scripts": { diff --git a/src/config-aliyun-acm/composer.json b/src/config-aliyun-acm/composer.json index 746e9673a..d48b44434 100644 --- a/src/config-aliyun-acm/composer.json +++ b/src/config-aliyun-acm/composer.json @@ -47,7 +47,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\ConfigAliyunAcm\\ConfigProvider" diff --git a/src/config-apollo/composer.json b/src/config-apollo/composer.json index 65aa43857..e807fa68c 100644 --- a/src/config-apollo/composer.json +++ b/src/config-apollo/composer.json @@ -46,7 +46,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\ConfigApollo\\ConfigProvider" diff --git a/src/config-etcd/composer.json b/src/config-etcd/composer.json index 57ce75cd6..275da3195 100644 --- a/src/config-etcd/composer.json +++ b/src/config-etcd/composer.json @@ -41,7 +41,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\ConfigEtcd\\ConfigProvider" diff --git a/src/config/composer.json b/src/config/composer.json index 527edf5ed..727d96557 100644 --- a/src/config/composer.json +++ b/src/config/composer.json @@ -52,7 +52,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Config\\ConfigProvider" diff --git a/src/constants/composer.json b/src/constants/composer.json index 01a712bbf..5f484f59c 100644 --- a/src/constants/composer.json +++ b/src/constants/composer.json @@ -37,7 +37,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { } diff --git a/src/consul/composer.json b/src/consul/composer.json index 09cac4752..2cb31cbd8 100644 --- a/src/consul/composer.json +++ b/src/consul/composer.json @@ -38,7 +38,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Consul\\ConfigProvider" diff --git a/src/contract/composer.json b/src/contract/composer.json index 9cb3573c8..32ff3b472 100644 --- a/src/contract/composer.json +++ b/src/contract/composer.json @@ -34,7 +34,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { } diff --git a/src/crontab/composer.json b/src/crontab/composer.json index 20d4a2881..5829675c1 100644 --- a/src/crontab/composer.json +++ b/src/crontab/composer.json @@ -37,7 +37,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Crontab\\ConfigProvider" diff --git a/src/database/composer.json b/src/database/composer.json index c1f6aac0f..c862a0670 100644 --- a/src/database/composer.json +++ b/src/database/composer.json @@ -42,7 +42,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" } }, "bin": [ diff --git a/src/db-connection/composer.json b/src/db-connection/composer.json index 1338d2033..a8ced667e 100644 --- a/src/db-connection/composer.json +++ b/src/db-connection/composer.json @@ -42,7 +42,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\DbConnection\\ConfigProvider" diff --git a/src/devtool/composer.json b/src/devtool/composer.json index 01451d549..9acedf042 100644 --- a/src/devtool/composer.json +++ b/src/devtool/composer.json @@ -39,7 +39,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Devtool\\ConfigProvider" diff --git a/src/di/composer.json b/src/di/composer.json index a6f653ae4..1fe808f6a 100644 --- a/src/di/composer.json +++ b/src/di/composer.json @@ -49,7 +49,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Di\\ConfigProvider" diff --git a/src/dispatcher/composer.json b/src/dispatcher/composer.json index c2ce185b6..13c0b2de3 100644 --- a/src/dispatcher/composer.json +++ b/src/dispatcher/composer.json @@ -42,7 +42,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Dispatcher\\ConfigProvider" diff --git a/src/elasticsearch/composer.json b/src/elasticsearch/composer.json index e657676b6..6d894a140 100644 --- a/src/elasticsearch/composer.json +++ b/src/elasticsearch/composer.json @@ -30,7 +30,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" } }, "scripts": { diff --git a/src/etcd/composer.json b/src/etcd/composer.json index e7f6e9fbf..ebc69cf6d 100644 --- a/src/etcd/composer.json +++ b/src/etcd/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Etcd\\ConfigProvider" diff --git a/src/event/composer.json b/src/event/composer.json index c1bd2e605..828abf059 100644 --- a/src/event/composer.json +++ b/src/event/composer.json @@ -40,7 +40,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Event\\ConfigProvider" diff --git a/src/exception-handler/composer.json b/src/exception-handler/composer.json index a2e4edb89..07706dd9a 100644 --- a/src/exception-handler/composer.json +++ b/src/exception-handler/composer.json @@ -35,7 +35,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\ExceptionHandler\\ConfigProvider" diff --git a/src/framework/composer.json b/src/framework/composer.json index 470c8778a..bff372f25 100644 --- a/src/framework/composer.json +++ b/src/framework/composer.json @@ -48,7 +48,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Framework\\ConfigProvider" diff --git a/src/graphql/composer.json b/src/graphql/composer.json index 4c8a2e1a9..d5dd12ffc 100644 --- a/src/graphql/composer.json +++ b/src/graphql/composer.json @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\GraphQL\\ConfigProvider" diff --git a/src/grpc-client/composer.json b/src/grpc-client/composer.json index f2bfb1967..7f660767c 100644 --- a/src/grpc-client/composer.json +++ b/src/grpc-client/composer.json @@ -40,7 +40,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\GrpcClient\\ConfigProvider" diff --git a/src/grpc-server/composer.json b/src/grpc-server/composer.json index 234fc249a..6964dd118 100644 --- a/src/grpc-server/composer.json +++ b/src/grpc-server/composer.json @@ -41,7 +41,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\GrpcServer\\ConfigProvider" diff --git a/src/grpc/composer.json b/src/grpc/composer.json index 0d963ed97..b0a6e626f 100644 --- a/src/grpc/composer.json +++ b/src/grpc/composer.json @@ -37,7 +37,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { } diff --git a/src/guzzle/composer.json b/src/guzzle/composer.json index ca1ff8f83..9c6e9b712 100644 --- a/src/guzzle/composer.json +++ b/src/guzzle/composer.json @@ -35,7 +35,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" } }, "scripts": { diff --git a/src/http-message/composer.json b/src/http-message/composer.json index 12d6f13ee..1d0df2270 100755 --- a/src/http-message/composer.json +++ b/src/http-message/composer.json @@ -32,7 +32,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { } diff --git a/src/http-server/composer.json b/src/http-server/composer.json index 4750b5e43..180ea40e1 100644 --- a/src/http-server/composer.json +++ b/src/http-server/composer.json @@ -48,7 +48,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\HttpServer\\ConfigProvider" diff --git a/src/json-rpc/composer.json b/src/json-rpc/composer.json index a4bd74bef..73190a486 100644 --- a/src/json-rpc/composer.json +++ b/src/json-rpc/composer.json @@ -48,7 +48,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\JsonRpc\\ConfigProvider" diff --git a/src/load-balancer/composer.json b/src/load-balancer/composer.json index 880ef2606..9e8ddaba0 100644 --- a/src/load-balancer/composer.json +++ b/src/load-balancer/composer.json @@ -37,7 +37,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\LoadBalancer\\ConfigProvider" diff --git a/src/logger/composer.json b/src/logger/composer.json index 9f57ef603..6f9b6e2e4 100644 --- a/src/logger/composer.json +++ b/src/logger/composer.json @@ -40,7 +40,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Logger\\ConfigProvider" diff --git a/src/memory/composer.json b/src/memory/composer.json index c70f69090..c104bfb17 100644 --- a/src/memory/composer.json +++ b/src/memory/composer.json @@ -35,7 +35,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Memory\\ConfigProvider" diff --git a/src/model-cache/composer.json b/src/model-cache/composer.json index 9331ae9f7..9385bf8ab 100644 --- a/src/model-cache/composer.json +++ b/src/model-cache/composer.json @@ -42,7 +42,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\ModelCache\\ConfigProvider" diff --git a/src/paginator/composer.json b/src/paginator/composer.json index 19f7a1913..a03b5c93d 100644 --- a/src/paginator/composer.json +++ b/src/paginator/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Paginator\\ConfigProvider" diff --git a/src/pool/composer.json b/src/pool/composer.json index 181e305ed..3c15cbb59 100644 --- a/src/pool/composer.json +++ b/src/pool/composer.json @@ -39,7 +39,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Pool\\ConfigProvider" diff --git a/src/process/composer.json b/src/process/composer.json index a644f64e4..b15192bf7 100644 --- a/src/process/composer.json +++ b/src/process/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Process\\ConfigProvider" diff --git a/src/rate-limit/composer.json b/src/rate-limit/composer.json index ca59a6b38..879a84996 100644 --- a/src/rate-limit/composer.json +++ b/src/rate-limit/composer.json @@ -47,7 +47,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\RateLimit\\ConfigProvider" diff --git a/src/redis/composer.json b/src/redis/composer.json index 17b39f7e9..dc6e448f5 100644 --- a/src/redis/composer.json +++ b/src/redis/composer.json @@ -42,7 +42,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Redis\\ConfigProvider" diff --git a/src/rpc-client/composer.json b/src/rpc-client/composer.json index cbe19cda5..4b4839706 100644 --- a/src/rpc-client/composer.json +++ b/src/rpc-client/composer.json @@ -44,7 +44,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\RpcClient\\ConfigProvider" diff --git a/src/rpc-server/composer.json b/src/rpc-server/composer.json index 92d31f4e6..3c64e4ec4 100644 --- a/src/rpc-server/composer.json +++ b/src/rpc-server/composer.json @@ -39,7 +39,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\RpcServer\\ConfigProvider" diff --git a/src/rpc/composer.json b/src/rpc/composer.json index 8ca2a799e..477ccfec1 100644 --- a/src/rpc/composer.json +++ b/src/rpc/composer.json @@ -38,7 +38,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { } diff --git a/src/server/composer.json b/src/server/composer.json index 4f6932530..a9e7ee8f6 100644 --- a/src/server/composer.json +++ b/src/server/composer.json @@ -45,7 +45,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Server\\ConfigProvider" diff --git a/src/service-governance/composer.json b/src/service-governance/composer.json index 1a7aa8ad2..9b6ad36c1 100644 --- a/src/service-governance/composer.json +++ b/src/service-governance/composer.json @@ -41,7 +41,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\ServiceGovernance\\ConfigProvider" diff --git a/src/swagger/composer.json b/src/swagger/composer.json index 28bcebac6..4b8121748 100644 --- a/src/swagger/composer.json +++ b/src/swagger/composer.json @@ -37,7 +37,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Swagger\\ConfigProvider" diff --git a/src/swoole-enterprise/composer.json b/src/swoole-enterprise/composer.json index ac67a084f..a72531b4c 100644 --- a/src/swoole-enterprise/composer.json +++ b/src/swoole-enterprise/composer.json @@ -41,7 +41,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\SwooleEnterprise\\ConfigProvider" diff --git a/src/task/composer.json b/src/task/composer.json index 1813dc74b..adbc86cc2 100644 --- a/src/task/composer.json +++ b/src/task/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Task\\ConfigProvider" diff --git a/src/testing/composer.json b/src/testing/composer.json index 5fd663efd..07d762eeb 100644 --- a/src/testing/composer.json +++ b/src/testing/composer.json @@ -35,7 +35,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" } }, "bin": [ diff --git a/src/tracer/composer.json b/src/tracer/composer.json index 444f7c586..52e1eb7b6 100644 --- a/src/tracer/composer.json +++ b/src/tracer/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Tracer\\ConfigProvider" diff --git a/src/utils/composer.json b/src/utils/composer.json index df0319fc2..e7c74a98b 100644 --- a/src/utils/composer.json +++ b/src/utils/composer.json @@ -50,7 +50,7 @@ "config": "Hyperf\\Utils\\ConfigProvider" }, "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" } }, "bin": [ diff --git a/src/view/composer.json b/src/view/composer.json index 9d350c040..2a54809a6 100644 --- a/src/view/composer.json +++ b/src/view/composer.json @@ -42,7 +42,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\View\\ConfigProvider" diff --git a/src/websocket-client/composer.json b/src/websocket-client/composer.json index 2aa245059..0e2b09050 100644 --- a/src/websocket-client/composer.json +++ b/src/websocket-client/composer.json @@ -42,7 +42,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\WebSocketClient\\ConfigProvider" diff --git a/src/websocket-server/composer.json b/src/websocket-server/composer.json index 289d11db5..1b09fee32 100644 --- a/src/websocket-server/composer.json +++ b/src/websocket-server/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\WebSocketServer\\ConfigProvider" From b3e585a73561788038465b0961688837a8ae4f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 15:50:57 +0800 Subject: [PATCH 004/225] Update ide version. --- composer.json | 2 +- src/elasticsearch/composer.json | 2 +- src/guzzle/composer.json | 2 +- src/http-message/composer.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 0d64ffa7a..5b4e2ebd0 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,7 @@ "mockery/mockery": "^1.0", "php-di/php-di": "^6.0", "phpunit/phpunit": "^7.0.0", - "swoft/swoole-ide-helper": "^4.3", + "swoft/swoole-ide-helper": "dev-master", "symfony/property-access": "^4.3", "symfony/serializer": "^4.3" }, diff --git a/src/elasticsearch/composer.json b/src/elasticsearch/composer.json index 6d894a140..0af639a6d 100644 --- a/src/elasticsearch/composer.json +++ b/src/elasticsearch/composer.json @@ -24,7 +24,7 @@ "elasticsearch/elasticsearch": "^6.1" }, "require-dev": { - "swoft/swoole-ide-helper": "~1.0.0", + "swoft/swoole-ide-helper": "dev-master", "phpunit/phpunit": "^5.7", "guzzlehttp/ringphp": "~1.0" }, diff --git a/src/guzzle/composer.json b/src/guzzle/composer.json index 9c6e9b712..fafe77c4d 100644 --- a/src/guzzle/composer.json +++ b/src/guzzle/composer.json @@ -26,7 +26,7 @@ "guzzlehttp/guzzle": "^6.3" }, "require-dev": { - "swoft/swoole-ide-helper": "~1.0.0", + "swoft/swoole-ide-helper": "dev-master", "phpunit/phpunit": "^5.7", "guzzlehttp/ringphp": "~1.0" }, diff --git a/src/http-message/composer.json b/src/http-message/composer.json index 1d0df2270..a236d1ad7 100755 --- a/src/http-message/composer.json +++ b/src/http-message/composer.json @@ -14,7 +14,7 @@ "zendframework/zend-mime": "^2.7" }, "require-dev": { - "swoft/swoole-ide-helper": "~1.0.0", + "swoft/swoole-ide-helper": "dev-master", "phpunit/phpunit": "^5.7" }, "autoload": { From dabe9d8c60aa8be14d1d705b3deac9e63fa4f432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 15:52:21 +0800 Subject: [PATCH 005/225] Update hyperf conponent version. --- src/amqp/composer.json | 14 +++++++------- src/async-queue/composer.json | 8 ++++---- src/cache/composer.json | 8 ++++---- src/circuit-breaker/composer.json | 6 +++--- src/command/composer.json | 2 +- src/config-aliyun-acm/composer.json | 12 ++++++------ src/config-apollo/composer.json | 12 ++++++------ src/config-etcd/composer.json | 4 ++-- src/config/composer.json | 10 +++++----- src/constants/composer.json | 4 ++-- src/consul/composer.json | 2 +- src/database/composer.json | 4 ++-- src/db-connection/composer.json | 12 ++++++------ src/devtool/composer.json | 8 ++++---- src/di/composer.json | 4 ++-- src/elasticsearch/composer.json | 2 +- src/etcd/composer.json | 2 +- src/event/composer.json | 4 ++-- src/exception-handler/composer.json | 6 +++--- src/framework/composer.json | 4 ++-- src/grpc-client/composer.json | 4 ++-- src/grpc-server/composer.json | 10 +++++----- src/http-server/composer.json | 16 ++++++++-------- src/json-rpc/composer.json | 10 +++++----- src/logger/composer.json | 4 ++-- src/model-cache/composer.json | 8 ++++---- src/paginator/composer.json | 10 +++++----- src/pool/composer.json | 4 ++-- src/process/composer.json | 6 +++--- src/rate-limit/composer.json | 10 +++++----- src/redis/composer.json | 8 ++++---- src/rpc-client/composer.json | 6 +++--- src/rpc-server/composer.json | 4 ++-- src/rpc/composer.json | 4 ++-- src/server/composer.json | 4 ++-- src/service-governance/composer.json | 6 +++--- src/swagger/composer.json | 2 +- src/swoole-enterprise/composer.json | 4 ++-- src/task/composer.json | 6 +++--- src/testing/composer.json | 8 ++++---- src/tracer/composer.json | 10 +++++----- src/utils/composer.json | 2 +- src/view/composer.json | 4 ++-- src/websocket-client/composer.json | 6 +++--- src/websocket-server/composer.json | 8 ++++---- 45 files changed, 146 insertions(+), 146 deletions(-) diff --git a/src/amqp/composer.json b/src/amqp/composer.json index ac3b7cb96..82324eaf7 100644 --- a/src/amqp/composer.json +++ b/src/amqp/composer.json @@ -11,10 +11,10 @@ }, "require": { "php": ">=7.2", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0", - "hyperf/process": "~1.0.0", - "hyperf/pool": "~1.0.0", + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0", + "hyperf/process": "~1.1.0", + "hyperf/pool": "~1.1.0", "psr/container": "^1.0", "psr/event-dispatcher": "^1.0", "psr/log": "^1.0", @@ -22,9 +22,9 @@ "doctrine/instantiator": "^1.2.0" }, "require-dev": { - "hyperf/di": "~1.0.0", - "hyperf/event": "~1.0.0", - "hyperf/framework": "~1.0.0", + "hyperf/di": "~1.1.0", + "hyperf/event": "~1.1.0", + "hyperf/framework": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/async-queue/composer.json b/src/async-queue/composer.json index 8c3f928a7..f2401b6ab 100644 --- a/src/async-queue/composer.json +++ b/src/async-queue/composer.json @@ -13,12 +13,12 @@ "php": ">=7.2", "psr/container": "^1.0", "psr/event-dispatcher": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/command": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/command": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { - "hyperf/process": "~1.0.0", + "hyperf/process": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/cache/composer.json b/src/cache/composer.json index 4aae816c9..82599a01c 100644 --- a/src/cache/composer.json +++ b/src/cache/composer.json @@ -13,12 +13,12 @@ "php": ">=7.2", "psr/container": "^1.0", "psr/simple-cache": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { - "hyperf/di": "~1.0.0", - "hyperf/event": "~1.0.0", + "hyperf/di": "~1.1.0", + "hyperf/event": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/circuit-breaker/composer.json b/src/circuit-breaker/composer.json index e9142061e..5c3c1bb71 100644 --- a/src/circuit-breaker/composer.json +++ b/src/circuit-breaker/composer.json @@ -12,11 +12,11 @@ "require": { "php": ">=7.2", "psr/container": "^1.0", - "hyperf/utils": "~1.0.0" + "hyperf/utils": "~1.1.0" }, "require-dev": { - "hyperf/contract": "~1.0.0", - "hyperf/di": "~1.0.0", + "hyperf/contract": "~1.1.0", + "hyperf/di": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/command/composer.json b/src/command/composer.json index 7596550fe..531e0fee5 100644 --- a/src/command/composer.json +++ b/src/command/composer.json @@ -20,7 +20,7 @@ "require": { "php": ">=7.2", "symfony/console": "^4.2", - "hyperf/utils": "~1.0.0" + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/config-aliyun-acm/composer.json b/src/config-aliyun-acm/composer.json index d48b44434..4d1b31b6a 100644 --- a/src/config-aliyun-acm/composer.json +++ b/src/config-aliyun-acm/composer.json @@ -16,14 +16,14 @@ "require": { "php": ">=7.2", "psr/container": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/guzzle": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/guzzle": "~1.1.0" }, "require-dev": { - "hyperf/config": "~1.0.0", - "hyperf/event": "~1.0.0", - "hyperf/framework": "~1.0.0", - "hyperf/process": "~1.0.0", + "hyperf/config": "~1.1.0", + "hyperf/event": "~1.1.0", + "hyperf/framework": "~1.1.0", + "hyperf/process": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/config-apollo/composer.json b/src/config-apollo/composer.json index e807fa68c..22e62aadd 100644 --- a/src/config-apollo/composer.json +++ b/src/config-apollo/composer.json @@ -15,14 +15,14 @@ "require": { "php": ">=7.2", "psr/container": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { - "hyperf/config": "~1.0.0", - "hyperf/event": "~1.0.0", - "hyperf/framework": "~1.0.0", - "hyperf/process": "~1.0.0", + "hyperf/config": "~1.1.0", + "hyperf/event": "~1.1.0", + "hyperf/framework": "~1.1.0", + "hyperf/process": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/config-etcd/composer.json b/src/config-etcd/composer.json index 275da3195..1d6b4ce16 100644 --- a/src/config-etcd/composer.json +++ b/src/config-etcd/composer.json @@ -22,8 +22,8 @@ "require": { "php": ">=7.2", "ext-swoole": ">=4.3", - "hyperf/utils": "~1.0.0", - "hyperf/etcd": "~1.0.0" + "hyperf/utils": "~1.1.0", + "hyperf/etcd": "~1.1.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", diff --git a/src/config/composer.json b/src/config/composer.json index 727d96557..0cdd88e32 100644 --- a/src/config/composer.json +++ b/src/config/composer.json @@ -16,13 +16,13 @@ "psr/container": "^1.0", "vlucas/phpdotenv": "^3.1", "symfony/finder": "^4.2.8", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { - "hyperf/di": "~1.0.0", - "hyperf/event": "~1.0.0", - "hyperf/framework": "~1.0.0", + "hyperf/di": "~1.1.0", + "hyperf/event": "~1.1.0", + "hyperf/framework": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/constants/composer.json b/src/constants/composer.json index 5f484f59c..37d49195d 100644 --- a/src/constants/composer.json +++ b/src/constants/composer.json @@ -11,8 +11,8 @@ }, "require": { "php": ">=7.2", - "hyperf/di": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/di": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/consul/composer.json b/src/consul/composer.json index 2cb31cbd8..1143c5186 100644 --- a/src/consul/composer.json +++ b/src/consul/composer.json @@ -13,7 +13,7 @@ }, "require": { "php": ">=7.2", - "hyperf/guzzle": "~1.0.0" + "hyperf/guzzle": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/database/composer.json b/src/database/composer.json index c862a0670..5c925aa0f 100644 --- a/src/database/composer.json +++ b/src/database/composer.json @@ -11,8 +11,8 @@ }, "require": { "php": ">=7.2", - "hyperf/utils": "~1.0.0", - "hyperf/paginator": "~1.0.0", + "hyperf/utils": "~1.1.0", + "hyperf/paginator": "~1.1.0", "psr/container": "^1.0", "nesbot/carbon": "^2.0", "psr/event-dispatcher": "^1.0" diff --git a/src/db-connection/composer.json b/src/db-connection/composer.json index a8ced667e..1c8a7feb3 100644 --- a/src/db-connection/composer.json +++ b/src/db-connection/composer.json @@ -12,12 +12,12 @@ }, "require": { "php": ">=7.2", - "hyperf/framework": "~1.0.0", - "hyperf/database": "~1.0.0", - "hyperf/di": "~1.0.0", - "hyperf/event": "~1.0.0", - "hyperf/pool": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/framework": "~1.1.0", + "hyperf/database": "~1.1.0", + "hyperf/di": "~1.1.0", + "hyperf/event": "~1.1.0", + "hyperf/pool": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/devtool/composer.json b/src/devtool/composer.json index 9acedf042..ab9710e89 100644 --- a/src/devtool/composer.json +++ b/src/devtool/composer.json @@ -12,10 +12,10 @@ }, "require": { "php": ">=7.2", - "hyperf/command": "~1.0.0", - "hyperf/contract": "~1.0.0", - "hyperf/di": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/command": "~1.1.0", + "hyperf/contract": "~1.1.0", + "hyperf/di": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/di/composer.json b/src/di/composer.json index 1fe808f6a..146e6c99e 100644 --- a/src/di/composer.json +++ b/src/di/composer.json @@ -19,8 +19,8 @@ "symfony/finder": "^4.1", "php-di/phpdoc-reader": "^2.0.1", "doctrine/instantiator": "^1.0", - "hyperf/event": "~1.0.0", - "hyperf/framework": "~1.0.0" + "hyperf/event": "~1.1.0", + "hyperf/framework": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/elasticsearch/composer.json b/src/elasticsearch/composer.json index 0af639a6d..c63063b59 100644 --- a/src/elasticsearch/composer.json +++ b/src/elasticsearch/composer.json @@ -20,7 +20,7 @@ }, "require": { "php": ">=7.0", - "hyperf/guzzle": "~1.0.0", + "hyperf/guzzle": "~1.1.0", "elasticsearch/elasticsearch": "^6.1" }, "require-dev": { diff --git a/src/etcd/composer.json b/src/etcd/composer.json index ebc69cf6d..4c7c88f87 100644 --- a/src/etcd/composer.json +++ b/src/etcd/composer.json @@ -21,7 +21,7 @@ "require": { "php": ">=7.2", "ext-swoole": ">=4.3", - "hyperf/utils": "~1.0.0" + "hyperf/utils": "~1.1.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", diff --git a/src/event/composer.json b/src/event/composer.json index 828abf059..2a57fd76a 100644 --- a/src/event/composer.json +++ b/src/event/composer.json @@ -13,10 +13,10 @@ "require": { "php": ">=7.2", "psr/event-dispatcher": "^1.0", - "hyperf/contract": "~1.0.0" + "hyperf/contract": "~1.1.0" }, "require-dev": { - "hyperf/di": "~1.0.0", + "hyperf/di": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/exception-handler/composer.json b/src/exception-handler/composer.json index 07706dd9a..c8f57a66c 100644 --- a/src/exception-handler/composer.json +++ b/src/exception-handler/composer.json @@ -21,9 +21,9 @@ "php": ">=7.2", "psr/container": "^1.0", "psr/http-message": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/dispatcher": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/dispatcher": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/framework/composer.json b/src/framework/composer.json index bff372f25..463d10573 100644 --- a/src/framework/composer.json +++ b/src/framework/composer.json @@ -16,8 +16,8 @@ "php": ">=7.2", "ext-swoole": ">=4.3", "fig/http-message-util": "^1.1.2", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0", + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0", "psr/container": "^1.0", "psr/event-dispatcher": "^1.0", "psr/log": "^1.0" diff --git a/src/grpc-client/composer.json b/src/grpc-client/composer.json index 7f660767c..2e2c8259d 100644 --- a/src/grpc-client/composer.json +++ b/src/grpc-client/composer.json @@ -13,8 +13,8 @@ }, "require": { "php": ">=7.2", - "hyperf/grpc": "~1.0.0", - "hyperf/utils": "~1.0.0", + "hyperf/grpc": "~1.1.0", + "hyperf/utils": "~1.1.0", "jean85/pretty-package-versions": "^1.2" }, "require-dev": { diff --git a/src/grpc-server/composer.json b/src/grpc-server/composer.json index 6964dd118..2451626e5 100644 --- a/src/grpc-server/composer.json +++ b/src/grpc-server/composer.json @@ -13,11 +13,11 @@ }, "require": { "php": ">=7.2", - "hyperf/di": "~1.0.0", - "hyperf/utils": "~1.0.0", - "hyperf/http-server": "~1.0.0", - "hyperf/http-message": "~1.0.0", - "hyperf/grpc": "~1.0.0" + "hyperf/di": "~1.1.0", + "hyperf/utils": "~1.1.0", + "hyperf/http-server": "~1.1.0", + "hyperf/http-message": "~1.1.0", + "hyperf/grpc": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/http-server/composer.json b/src/http-server/composer.json index 180ea40e1..58f56303c 100644 --- a/src/http-server/composer.json +++ b/src/http-server/composer.json @@ -15,16 +15,16 @@ "php": ">=7.2", "psr/container": "^1.0", "nikic/fast-route": "^1.3", - "hyperf/contract": "~1.0.0", - "hyperf/dispatcher": "~1.0.0", - "hyperf/event": "~1.0.0", - "hyperf/exception-handler": "~1.0.0", - "hyperf/http-message": "~1.0.0", - "hyperf/server": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/dispatcher": "~1.1.0", + "hyperf/event": "~1.1.0", + "hyperf/exception-handler": "~1.1.0", + "hyperf/http-message": "~1.1.0", + "hyperf/server": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { - "hyperf/di": "~1.0.0", + "hyperf/di": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/json-rpc/composer.json b/src/json-rpc/composer.json index 73190a486..57819055b 100644 --- a/src/json-rpc/composer.json +++ b/src/json-rpc/composer.json @@ -14,11 +14,11 @@ "php": ">=7.2", "psr/container": "^1.0", "psr/log": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/load-balancer": "~1.0.0", - "hyperf/http-message": "~1.0.0", - "hyperf/rpc": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/load-balancer": "~1.1.0", + "hyperf/http-message": "~1.1.0", + "hyperf/rpc": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/logger/composer.json b/src/logger/composer.json index 6f9b6e2e4..434dfba6f 100644 --- a/src/logger/composer.json +++ b/src/logger/composer.json @@ -13,8 +13,8 @@ "php": ">=7.2", "psr/log": "^1.0", "psr/container": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0", + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0", "monolog/monolog": "^1.24" }, "require-dev": { diff --git a/src/model-cache/composer.json b/src/model-cache/composer.json index 9385bf8ab..8872f84ae 100644 --- a/src/model-cache/composer.json +++ b/src/model-cache/composer.json @@ -13,12 +13,12 @@ "php": ">=7.2", "psr/simple-cache": "^1.0", "psr/container": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/db-connection": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/db-connection": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { - "hyperf/event": "~1.0.0", + "hyperf/event": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/paginator/composer.json b/src/paginator/composer.json index a03b5c93d..ae4712306 100644 --- a/src/paginator/composer.json +++ b/src/paginator/composer.json @@ -11,13 +11,13 @@ }, "require": { "php": ">=7.2", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { - "hyperf/event": "~1.0.0", - "hyperf/http-server": "~1.0.0", - "hyperf/framework": "~1.0.0", + "hyperf/event": "~1.1.0", + "hyperf/http-server": "~1.1.0", + "hyperf/framework": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/pool/composer.json b/src/pool/composer.json index 3c15cbb59..ba49b49f1 100644 --- a/src/pool/composer.json +++ b/src/pool/composer.json @@ -13,8 +13,8 @@ "require": { "php": ">=7.2", "psr/container": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/process/composer.json b/src/process/composer.json index b15192bf7..873bf227c 100644 --- a/src/process/composer.json +++ b/src/process/composer.json @@ -13,11 +13,11 @@ "php": ">=7.2", "psr/container": "^1.0", "psr/event-dispatcher": "^1.0", - "hyperf/contract": "~1.0.0" + "hyperf/contract": "~1.1.0" }, "require-dev": { - "hyperf/di": "~1.0.0", - "hyperf/event": "~1.0.0", + "hyperf/di": "~1.1.0", + "hyperf/event": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/rate-limit/composer.json b/src/rate-limit/composer.json index 879a84996..7c009f32d 100644 --- a/src/rate-limit/composer.json +++ b/src/rate-limit/composer.json @@ -14,7 +14,7 @@ "php": ">=7.2", "psr/container": "^1.0", "psr/simple-cache": "^1.0", - "hyperf/utils": "~1.0.0", + "hyperf/utils": "~1.1.0", "bandwidth-throttle/token-bucket": "^2.0" }, "require-dev": { @@ -22,10 +22,10 @@ "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", "friendsofphp/php-cs-fixer": "^2.9", - "hyperf/contract": "~1.0.0", - "hyperf/di": "~1.0.0", - "hyperf/http-server": "~1.0.0", - "hyperf/redis": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/di": "~1.1.0", + "hyperf/http-server": "~1.1.0", + "hyperf/redis": "~1.1.0" }, "suggest": { "hyperf/contract": "Required to use annotations.", diff --git a/src/redis/composer.json b/src/redis/composer.json index dc6e448f5..b11f3d6d7 100644 --- a/src/redis/composer.json +++ b/src/redis/composer.json @@ -13,12 +13,12 @@ "require": { "php": ">=7.2", "psr/container": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/pool": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/pool": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { - "hyperf/di": "~1.0.0", + "hyperf/di": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/rpc-client/composer.json b/src/rpc-client/composer.json index 4b4839706..12c321dde 100644 --- a/src/rpc-client/composer.json +++ b/src/rpc-client/composer.json @@ -15,9 +15,9 @@ "require": { "php": ">=7.2", "psr/container": "^1.0", - "hyperf/rpc": "~1.0.0", - "hyperf/load-balancer": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/rpc": "~1.1.0", + "hyperf/load-balancer": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/rpc-server/composer.json b/src/rpc-server/composer.json index 3c64e4ec4..39d6d7cc1 100644 --- a/src/rpc-server/composer.json +++ b/src/rpc-server/composer.json @@ -13,8 +13,8 @@ }, "require": { "php": ">=7.2", - "hyperf/http-server": "~1.0.0", - "hyperf/rpc": "~1.0.0" + "hyperf/http-server": "~1.1.0", + "hyperf/rpc": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/rpc/composer.json b/src/rpc/composer.json index 477ccfec1..09088c335 100644 --- a/src/rpc/composer.json +++ b/src/rpc/composer.json @@ -12,8 +12,8 @@ }, "require": { "php": ">=7.2", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/server/composer.json b/src/server/composer.json index a9e7ee8f6..86a9d73e6 100644 --- a/src/server/composer.json +++ b/src/server/composer.json @@ -17,8 +17,8 @@ "psr/log": "^1.0", "psr/event-dispatcher": "^1.0", "symfony/console": "^4.2", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/service-governance/composer.json b/src/service-governance/composer.json index 9b6ad36c1..4d646331d 100644 --- a/src/service-governance/composer.json +++ b/src/service-governance/composer.json @@ -12,11 +12,11 @@ }, "require": { "php": ">=7.2", - "hyperf/consul": "~1.0.0", - "hyperf/contract": "~1.0.0" + "hyperf/consul": "~1.1.0", + "hyperf/contract": "~1.1.0" }, "require-dev": { - "hyperf/event": "~1.0.0", + "hyperf/event": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/swagger/composer.json b/src/swagger/composer.json index 4b8121748..2d03c34fc 100644 --- a/src/swagger/composer.json +++ b/src/swagger/composer.json @@ -12,7 +12,7 @@ }, "require": { "php": ">=7.2", - "hyperf/command": "~1.0.0", + "hyperf/command": "~1.1.0", "zircote/swagger-php": "^3.0" }, "require-dev": { diff --git a/src/swoole-enterprise/composer.json b/src/swoole-enterprise/composer.json index a72531b4c..73c8a2727 100644 --- a/src/swoole-enterprise/composer.json +++ b/src/swoole-enterprise/composer.json @@ -13,8 +13,8 @@ "require": { "php": ">=7.2", "ext-swoole": ">=4.3", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0", + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0", "psr/container": "^1.0", "psr/http-server-middleware": "^1.0", "psr/log": "^1.0" diff --git a/src/task/composer.json b/src/task/composer.json index adbc86cc2..1c7b864aa 100644 --- a/src/task/composer.json +++ b/src/task/composer.json @@ -12,9 +12,9 @@ }, "require": { "php": ">=7.2", - "hyperf/contract": "~1.0.0", - "hyperf/framework": "~1.0.0", - "hyperf/utils": "~1.0.0", + "hyperf/contract": "~1.1.0", + "hyperf/framework": "~1.1.0", + "hyperf/utils": "~1.1.0", "psr/container": "^1.0", "psr/log": "^1.0", "psr/event-dispatcher": "^1.0" diff --git a/src/testing/composer.json b/src/testing/composer.json index 07d762eeb..8f8f9409d 100644 --- a/src/testing/composer.json +++ b/src/testing/composer.json @@ -21,10 +21,10 @@ "php": ">=7.2", "psr/container": "^1.0", "phpunit/phpunit": "^7.0", - "hyperf/contract": "~1.0.0", - "hyperf/http-message": "~1.0.0", - "hyperf/http-server": "~1.0.0", - "hyperf/utils": "~1.0.0" + "hyperf/contract": "~1.1.0", + "hyperf/http-message": "~1.1.0", + "hyperf/http-server": "~1.1.0", + "hyperf/utils": "~1.1.0" }, "require-dev": { "malukenho/docheader": "^0.1.6", diff --git a/src/tracer/composer.json b/src/tracer/composer.json index 52e1eb7b6..fabaf0584 100644 --- a/src/tracer/composer.json +++ b/src/tracer/composer.json @@ -13,14 +13,14 @@ "require": { "php": ">=7.2", "psr/http-message": "^1.0", - "hyperf/contract": "~1.0.0", - "hyperf/di": "~1.0.0", - "hyperf/guzzle": "~1.0.0", - "hyperf/utils": "~1.0.0", + "hyperf/contract": "~1.1.0", + "hyperf/di": "~1.1.0", + "hyperf/guzzle": "~1.1.0", + "hyperf/utils": "~1.1.0", "openzipkin/zipkin": "^1.3.2" }, "require-dev": { - "hyperf/event": "~1.0.0", + "hyperf/event": "~1.1.0", "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "phpunit/phpunit": "^7.0.0", diff --git a/src/utils/composer.json b/src/utils/composer.json index e7c74a98b..1f707ed09 100644 --- a/src/utils/composer.json +++ b/src/utils/composer.json @@ -13,7 +13,7 @@ "require": { "php": ">=7.2", "doctrine/inflector": "^1.3", - "hyperf/contract": "~1.0.0" + "hyperf/contract": "~1.1.0" }, "require-dev": { "symfony/var-dumper": "^4.1", diff --git a/src/view/composer.json b/src/view/composer.json index 2a54809a6..89d9baca3 100644 --- a/src/view/composer.json +++ b/src/view/composer.json @@ -12,8 +12,8 @@ }, "require": { "php": ">=7.2", - "hyperf/contract": "~1.0.0", - "hyperf/utils": "~1.0.0", + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0", "psr/container": "^1.0", "psr/log": "^1.0" }, diff --git a/src/websocket-client/composer.json b/src/websocket-client/composer.json index 0e2b09050..d06c33141 100644 --- a/src/websocket-client/composer.json +++ b/src/websocket-client/composer.json @@ -13,9 +13,9 @@ "require": { "php": ">=7.2", "ext-swoole": ">=4.3", - "hyperf/contract": "~1.0.0", - "hyperf/http-message": "~1.0.0", - "hyperf/utils": "~1.0.0", + "hyperf/contract": "~1.1.0", + "hyperf/http-message": "~1.1.0", + "hyperf/utils": "~1.1.0", "psr/container": "^1.0", "psr/log": "^1.0" }, diff --git a/src/websocket-server/composer.json b/src/websocket-server/composer.json index 1b09fee32..b4ae28152 100644 --- a/src/websocket-server/composer.json +++ b/src/websocket-server/composer.json @@ -13,10 +13,10 @@ "require": { "php": ">=7.2", "ext-swoole": ">=4.3", - "hyperf/contract": "~1.0.0", - "hyperf/exception-handler": "~1.0.0", - "hyperf/http-server": "~1.0.0", - "hyperf/utils": "~1.0.0", + "hyperf/contract": "~1.1.0", + "hyperf/exception-handler": "~1.1.0", + "hyperf/http-server": "~1.1.0", + "hyperf/utils": "~1.1.0", "psr/container": "^1.0", "psr/event-dispatcher": "^1.0", "psr/log": "^1.0" From 3c4fda46268c6d25c90dcb1c9ce6237d08bc182d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 15:58:44 +0800 Subject: [PATCH 006/225] Update .travis.yml --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 38dd226b9..c9b0bfddc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,3 @@ -branches: - only: - - master - language: php sudo: required From be34c1a1b36768a6844e5cc0c45d295bf09a75da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 17:35:03 +0800 Subject: [PATCH 007/225] Fixed middleware that user defined does not works. --- src/http-server/src/CoreMiddleware.php | 40 ++++++------ src/http-server/src/Router/Dispatched.php | 61 +++++++++++++++++++ .../src/Router/DispatcherFactory.php | 28 +++------ src/http-server/src/Router/Handler.php | 32 ++++++++++ src/http-server/src/Router/RouteCollector.php | 4 +- src/http-server/src/Server.php | 23 +++++-- src/json-rpc/src/CoreMiddleware.php | 9 +-- src/rpc-server/src/CoreMiddleware.php | 9 +-- src/rpc-server/src/Router/RouteCollector.php | 5 +- src/websocket-server/src/CoreMiddleware.php | 5 +- 10 files changed, 158 insertions(+), 58 deletions(-) create mode 100644 src/http-server/src/Router/Dispatched.php create mode 100644 src/http-server/src/Router/Handler.php diff --git a/src/http-server/src/CoreMiddleware.php b/src/http-server/src/CoreMiddleware.php index 0b2223a47..8f69403de 100644 --- a/src/http-server/src/CoreMiddleware.php +++ b/src/http-server/src/CoreMiddleware.php @@ -17,7 +17,10 @@ use FastRoute\Dispatcher; use Hyperf\Contract\NormalizerInterface; use Hyperf\Di\MethodDefinitionCollectorInterface; use Hyperf\HttpMessage\Stream\SwooleStream; +use Hyperf\HttpServer\Router\Dispatched; use Hyperf\HttpServer\Router\DispatcherFactory; +use Hyperf\HttpServer\Router\Handler; +use Hyperf\Server\Exception\ServerException; use Hyperf\Utils\Context; use Hyperf\Utils\Contracts\Arrayable; use Hyperf\Utils\Contracts\Jsonable; @@ -69,25 +72,22 @@ class CoreMiddleware implements MiddlewareInterface */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { - /** @var ResponseInterface $response */ - $uri = $request->getUri(); - /** - * @var array - * Returns array with one of the following formats: - * [self::NOT_FOUND] - * [self::METHOD_NOT_ALLOWED, ['GET', 'OTHER_ALLOWED_METHODS']] - * [self::FOUND, $handler, ['varName' => 'value', ...]] - */ - $routes = $this->dispatcher->dispatch($request->getMethod(), $uri->getPath()); - switch ($routes[0]) { + /** @var Dispatched $dispatched */ + $dispatched = $request->getAttribute(Dispatched::class); + + if (! $dispatched instanceof Dispatched) { + throw new ServerException('Dispatch failed.'); + } + + switch ($dispatched->status) { case Dispatcher::NOT_FOUND: $response = $this->handleNotFound($request); break; case Dispatcher::METHOD_NOT_ALLOWED: - $response = $this->handleMethodNotAllowed($routes, $request); + $response = $this->handleMethodNotAllowed($dispatched->params, $request); break; case Dispatcher::FOUND: - $response = $this->handleFound($routes, $request); + $response = $this->handleFound($dispatched, $request); break; } if (! $response instanceof ResponseInterface) { @@ -117,18 +117,18 @@ class CoreMiddleware implements MiddlewareInterface * * @return array|Arrayable|mixed|ResponseInterface|string */ - protected function handleFound(array $routes, ServerRequestInterface $request) + protected function handleFound(Dispatched $dispatched, ServerRequestInterface $request) { - if ($routes[1] instanceof Closure) { - $response = call($routes[1]); + if ($dispatched->handler->callback instanceof Closure) { + $response = call($dispatched->handler->callback); } else { - [$controller, $action] = $this->prepareHandler($routes[1]); + [$controller, $action] = $this->prepareHandler($dispatched->handler->callback); $controllerInstance = $this->container->get($controller); if (! method_exists($controller, $action)) { // Route found, but the handler does not exist. return $this->response()->withStatus(500)->withBody(new SwooleStream('Method of class does not exist.')); } - $parameters = $this->parseParameters($controller, $action, $routes[2]); + $parameters = $this->parseParameters($controller, $action, $dispatched->params); $response = $controllerInstance->{$action}(...$parameters); } return $response; @@ -149,9 +149,9 @@ class CoreMiddleware implements MiddlewareInterface * * @return array|Arrayable|mixed|ResponseInterface|string */ - protected function handleMethodNotAllowed(array $routes, ServerRequestInterface $request) + protected function handleMethodNotAllowed(array $methods, ServerRequestInterface $request) { - return $this->response()->withStatus(405)->withAddedHeader('Allow', implode(', ', $routes[1])); + return $this->response()->withStatus(405)->withAddedHeader('Allow', implode(', ', $methods)); } /** diff --git a/src/http-server/src/Router/Dispatched.php b/src/http-server/src/Router/Dispatched.php new file mode 100644 index 000000000..85b02de91 --- /dev/null +++ b/src/http-server/src/Router/Dispatched.php @@ -0,0 +1,61 @@ + 'value', ...]] + */ + public function __construct(array $array) + { + $this->status = $array[0]; + switch ($this->status) { + case Dispatcher::METHOD_NOT_ALLOWED: + $this->params = $array[1]; + break; + case Dispatcher::FOUND: + $this->handler = $array[1]; + $this->params = $array[2]; + break; + } + } + + public function isFind() + { + return $this->status == Dispatcher::FOUND; + } +} diff --git a/src/http-server/src/Router/DispatcherFactory.php b/src/http-server/src/Router/DispatcherFactory.php index 5a0e850f7..dbc056297 100644 --- a/src/http-server/src/Router/DispatcherFactory.php +++ b/src/http-server/src/Router/DispatcherFactory.php @@ -30,7 +30,6 @@ use Hyperf\HttpServer\Annotation\PatchMapping; use Hyperf\HttpServer\Annotation\PostMapping; use Hyperf\HttpServer\Annotation\PutMapping; use Hyperf\HttpServer\Annotation\RequestMapping; -use Hyperf\HttpServer\MiddlewareManager; use Hyperf\Utils\Str; use ReflectionMethod; @@ -118,7 +117,6 @@ class DispatcherFactory foreach ($methods as $method) { $path = $this->parsePath($prefix, $method); $methodName = $method->getName(); - $router->addRoute($autoMethods, $path, [$className, $methodName, $annotation->server]); $methodMiddlewares = $middlewares; // Handle method level middlewares. @@ -127,16 +125,15 @@ class DispatcherFactory $methodMiddlewares = array_unique($methodMiddlewares); } - // Register middlewares. - foreach ($autoMethods as $autoMethod) { - MiddlewareManager::addMiddlewares($annotation->server, $path, $autoMethod, $methodMiddlewares); - } + $router->addRoute($autoMethods, $path, [$className, $methodName], [ + 'middleware' => $methodMiddlewares, + ]); + if (Str::endsWith($path, $defaultAction)) { $path = Str::replaceLast($defaultAction, '', $path); - $router->addRoute($autoMethods, $path, [$className, $methodName, $annotation->server]); - foreach ($autoMethods as $autoMethod) { - MiddlewareManager::addMiddlewares($annotation->server, $path, $autoMethod, $methodMiddlewares); - } + $router->addRoute($autoMethods, $path, [$className, $methodName], [ + 'middleware' => $methodMiddlewares, + ]); } } } @@ -180,16 +177,9 @@ class DispatcherFactory if ($path[0] !== '/') { $path = $prefix . '/' . $path; } - $router->addRoute($mapping->methods, $path, [ - $className, - $methodName, - $annotation->server, + $router->addRoute($mapping->methods, $path, [$className, $methodName], [ + 'middleware' => $methodMiddlewares, ]); - - // Register middlewares. - foreach ($mapping->methods as $mappingMethod) { - MiddlewareManager::addMiddlewares($annotation->server, $path, $mappingMethod, $methodMiddlewares); - } } } } diff --git a/src/http-server/src/Router/Handler.php b/src/http-server/src/Router/Handler.php new file mode 100644 index 000000000..565132c1e --- /dev/null +++ b/src/http-server/src/Router/Handler.php @@ -0,0 +1,32 @@ +callback = $callback; + $this->route = $route; + } +} diff --git a/src/http-server/src/Router/RouteCollector.php b/src/http-server/src/Router/RouteCollector.php index 933328113..4faf783d2 100644 --- a/src/http-server/src/Router/RouteCollector.php +++ b/src/http-server/src/Router/RouteCollector.php @@ -74,8 +74,8 @@ class RouteCollector foreach ((array) $httpMethod as $method) { $method = strtoupper($method); foreach ($routeDatas as $routeData) { - $this->dataGenerator->addRoute($method, $routeData, $handler); - MiddlewareManager::addMiddlewares($this->server, $routeData[0], $method, $options['middleware'] ?? []); + $this->dataGenerator->addRoute($method, $routeData, new Handler($handler, $route)); + MiddlewareManager::addMiddlewares($this->server, $route, $method, $options['middleware'] ?? []); } } } diff --git a/src/http-server/src/Server.php b/src/http-server/src/Server.php index c4cbd2f76..56a435b5b 100644 --- a/src/http-server/src/Server.php +++ b/src/http-server/src/Server.php @@ -21,7 +21,9 @@ use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler; +use Hyperf\HttpServer\Router\Dispatched; use Hyperf\HttpServer\Router\DispatcherFactory; +use Hyperf\HttpServer\Router\Handler; use Hyperf\Utils\Context; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; @@ -90,9 +92,17 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface try { [$psr7Request, $psr7Response] = $this->initRequestAndResponse($request, $response); - $psr7Request = $this->parse($psr7Request); - - $middlewares = array_merge($this->middlewares, MiddlewareManager::get($this->serverName, $psr7Request->getUri()->getPath(), $psr7Request->getMethod())); + /** + * @var array + * @var ServerRequestInterface $psr7Request + * @var Dispatched $dispatched + */ + [$psr7Request, $dispatched] = $this->parse($psr7Request); + $middlewares = $this->middlewares; + if ($dispatched->isFind()) { + $registedMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod()); + $middlewares = array_merge($middlewares, $registedMiddlewares); + } $psr7Response = $this->dispatcher->dispatch($psr7Request, $middlewares, $this->coreMiddleware); } catch (Throwable $throwable) { @@ -128,13 +138,16 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface return $factory->getDispatcher($serverName); } - protected function parse(ServerRequestInterface $request): ServerRequestInterface + protected function parse(ServerRequestInterface $request): array { $uri = $request->getUri(); $routes = $this->routerDispatcher->dispatch($request->getMethod(), $uri->getPath()); - return $request->withAttribute('routes', $routes); + $dispatched = new Dispatched($routes); + $request = $request->withAttribute(Dispatched::class, $dispatched); + + return [$request, $dispatched]; } protected function getDefaultExceptionHandler(): array diff --git a/src/json-rpc/src/CoreMiddleware.php b/src/json-rpc/src/CoreMiddleware.php index 81a00d1a9..5958eee3b 100644 --- a/src/json-rpc/src/CoreMiddleware.php +++ b/src/json-rpc/src/CoreMiddleware.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Hyperf\JsonRpc; use Closure; +use Hyperf\HttpServer\Router\Dispatched; use Hyperf\Rpc\Protocol; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; @@ -34,12 +35,12 @@ class CoreMiddleware extends \Hyperf\RpcServer\CoreMiddleware ]); } - protected function handleFound(array $routes, ServerRequestInterface $request) + protected function handleFound(Dispatched $dispatched, ServerRequestInterface $request) { - if ($routes[1] instanceof Closure) { - $response = call($routes[1]); + if ($dispatched->handler->callback instanceof Closure) { + $response = call($dispatched->handler->callback); } else { - [$controller, $action] = $this->prepareHandler($routes[1]); + [$controller, $action] = $this->prepareHandler($dispatched->handler->callback); $controllerInstance = $this->container->get($controller); if (! method_exists($controller, $action)) { // Route found, but the handler does not exist. diff --git a/src/rpc-server/src/CoreMiddleware.php b/src/rpc-server/src/CoreMiddleware.php index d4e591943..9d00513ed 100644 --- a/src/rpc-server/src/CoreMiddleware.php +++ b/src/rpc-server/src/CoreMiddleware.php @@ -15,6 +15,7 @@ namespace Hyperf\RpcServer; use Closure; use FastRoute\Dispatcher; use Hyperf\HttpMessage\Stream\SwooleStream; +use Hyperf\HttpServer\Router\Dispatched; use Hyperf\Rpc\Protocol; use Hyperf\RpcServer\Router\DispatcherFactory; use Psr\Container\ContainerInterface; @@ -47,12 +48,12 @@ class CoreMiddleware extends \Hyperf\HttpServer\CoreMiddleware return $factory->getDispatcher($serverName); } - protected function handleFound(array $routes, ServerRequestInterface $request) + protected function handleFound(Dispatched $dispatched, ServerRequestInterface $request) { - if ($routes[1] instanceof Closure) { - $response = call($routes[1]); + if ($dispatched->handler->callback instanceof Closure) { + $response = call($dispatched->handler->callback); } else { - [$controller, $action] = $this->prepareHandler($routes[1]); + [$controller, $action] = $this->prepareHandler($dispatched->handler->callback); $controllerInstance = $this->container->get($controller); if (! method_exists($controller, $action)) { // Route found, but the handler does not exist. diff --git a/src/rpc-server/src/Router/RouteCollector.php b/src/rpc-server/src/Router/RouteCollector.php index d17e2f438..7d1ee5e3d 100644 --- a/src/rpc-server/src/Router/RouteCollector.php +++ b/src/rpc-server/src/Router/RouteCollector.php @@ -15,6 +15,7 @@ namespace Hyperf\RpcServer\Router; use FastRoute\DataGenerator; use FastRoute\RouteParser; use Hyperf\HttpServer\MiddlewareManager; +use Hyperf\HttpServer\Router\Handler; class RouteCollector { @@ -68,8 +69,8 @@ class RouteCollector $server = $options['server'] ?? 'rpc'; foreach ($routeDatas as $routeData) { // Use 'GET' method for RPC. - $this->dataGenerator->addRoute('POST', $routeData, $handler); - MiddlewareManager::addMiddlewares($server, $routeData[0], 'GET', $options['middleware'] ?? []); + $this->dataGenerator->addRoute('POST', $routeData, new Handler($handler, $route)); + MiddlewareManager::addMiddlewares($server, $route, 'GET', $options['middleware'] ?? []); } } diff --git a/src/websocket-server/src/CoreMiddleware.php b/src/websocket-server/src/CoreMiddleware.php index a5d4f9bbd..c2a46265b 100644 --- a/src/websocket-server/src/CoreMiddleware.php +++ b/src/websocket-server/src/CoreMiddleware.php @@ -14,6 +14,7 @@ namespace Hyperf\WebSocketServer; use FastRoute\Dispatcher; use Hyperf\HttpServer\CoreMiddleware as HttpCoreMiddleware; +use Hyperf\HttpServer\Router\Dispatched; use Hyperf\Utils\Context; use Hyperf\Utils\Contracts\Arrayable; use Hyperf\WebSocketServer\Exception\WebSocketHandeShakeException; @@ -63,9 +64,9 @@ class CoreMiddleware extends HttpCoreMiddleware * * @return array|Arrayable|mixed|ResponseInterface|string */ - protected function handleFound(array $routes, ServerRequestInterface $request): ResponseInterface + protected function handleFound(Dispatched $dispatched, ServerRequestInterface $request): ResponseInterface { - [$controller,] = $this->prepareHandler($routes[1]); + [$controller,] = $this->prepareHandler($dispatched->handler->callback); if (! $this->container->has($controller)) { throw new WebSocketHandeShakeException('Router not exist.'); } From 18f3ccf41a28f48c1ac0617ef11fdb20a3629159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 18:15:46 +0800 Subject: [PATCH 008/225] Fixed testing. --- src/http-server/src/CoreMiddleware.php | 12 ++++++++++++ src/http-server/src/Server.php | 14 +------------- .../tests/Router/RouteCollectorTest.php | 18 +++++++++++------- src/json-rpc/src/TcpServer.php | 19 +++++++++++++------ src/json-rpc/src/TcpServerFactory.php | 6 +----- .../tests/AnyParamCoreMiddlewareTest.php | 11 +++++++++++ src/rpc-server/src/Server.php | 17 ++--------------- 7 files changed, 51 insertions(+), 46 deletions(-) diff --git a/src/http-server/src/CoreMiddleware.php b/src/http-server/src/CoreMiddleware.php index 8f69403de..5fa03894f 100644 --- a/src/http-server/src/CoreMiddleware.php +++ b/src/http-server/src/CoreMiddleware.php @@ -66,6 +66,18 @@ class CoreMiddleware implements MiddlewareInterface $this->methodDefinitionCollector = $this->container->get(MethodDefinitionCollectorInterface::class); } + public function dispatch(ServerRequestInterface $request): array + { + $uri = $request->getUri(); + + $routes = $this->dispatcher->dispatch($request->getMethod(), $uri->getPath()); + + $dispatched = new Dispatched($routes); + $request = $request->withAttribute(Dispatched::class, $dispatched); + + return [$request, $dispatched]; + } + /** * Process an incoming server request and return a response, optionally delegating * response creation to a handler. diff --git a/src/http-server/src/Server.php b/src/http-server/src/Server.php index 56a435b5b..b3eb238a7 100644 --- a/src/http-server/src/Server.php +++ b/src/http-server/src/Server.php @@ -97,7 +97,7 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface * @var ServerRequestInterface $psr7Request * @var Dispatched $dispatched */ - [$psr7Request, $dispatched] = $this->parse($psr7Request); + [$psr7Request, $dispatched] = $this->coreMiddleware->dispatch($psr7Request); $middlewares = $this->middlewares; if ($dispatched->isFind()) { $registedMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod()); @@ -138,18 +138,6 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface return $factory->getDispatcher($serverName); } - protected function parse(ServerRequestInterface $request): array - { - $uri = $request->getUri(); - - $routes = $this->routerDispatcher->dispatch($request->getMethod(), $uri->getPath()); - - $dispatched = new Dispatched($routes); - $request = $request->withAttribute(Dispatched::class, $dispatched); - - return [$request, $dispatched]; - } - protected function getDefaultExceptionHandler(): array { return [ diff --git a/src/http-server/tests/Router/RouteCollectorTest.php b/src/http-server/tests/Router/RouteCollectorTest.php index 44799be00..cdf78a3ff 100644 --- a/src/http-server/tests/Router/RouteCollectorTest.php +++ b/src/http-server/tests/Router/RouteCollectorTest.php @@ -46,10 +46,10 @@ class RouteCollectorTest extends TestCase }); $data = $collector->getData()[0]; - $this->assertSame('Handler::Get', $data['GET']['/']); - $this->assertSame('Handler::ApiGet', $data['GET']['/api/']); - $this->assertSame('Handler::Post', $data['POST']['/']); - $this->assertSame('Handler::ApiPost', $data['POST']['/api/']); + $this->assertSame('Handler::Get', $data['GET']['/']->callback); + $this->assertSame('Handler::ApiGet', $data['GET']['/api/']->callback); + $this->assertSame('Handler::Post', $data['POST']['/']->callback); + $this->assertSame('Handler::ApiPost', $data['POST']['/api/']->callback); } public function testAddGroupMiddleware() @@ -71,16 +71,20 @@ class RouteCollectorTest extends TestCase $collector->post('/', 'Handler::Post', [ 'middleware' => ['PostMiddleware'], ]); + $collector->post('/user/{id:\d+}', 'Handler::Post', [ + 'middleware' => ['PostMiddleware'], + ]); $data = $collector->getData()[0]; - $this->assertSame('Handler::Get', $data['GET']['/']); - $this->assertSame('Handler::ApiGet', $data['GET']['/api/']); - $this->assertSame('Handler::Post', $data['POST']['/']); + $this->assertSame('Handler::Get', $data['GET']['/']->callback); + $this->assertSame('Handler::ApiGet', $data['GET']['/api/']->callback); + $this->assertSame('Handler::Post', $data['POST']['/']->callback); $middle = MiddlewareManager::$container; $this->assertSame(['GetMiddleware'], $middle['http']['/']['GET']); $this->assertSame(['PostMiddleware'], $middle['http']['/']['POST']); $this->assertSame(['ApiGetMiddleware', 'ApiSelfGetMiddleware'], $middle['http']['/api/']['GET']); + $this->assertSame(['PostMiddleware'], $middle['http']['/user/{id:\d+}']['POST']); } public function testAddGroupMiddlewareFromAnotherServer() diff --git a/src/json-rpc/src/TcpServer.php b/src/json-rpc/src/TcpServer.php index 0d4769b8f..7c07ffa85 100644 --- a/src/json-rpc/src/TcpServer.php +++ b/src/json-rpc/src/TcpServer.php @@ -18,11 +18,13 @@ use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpMessage\Uri\Uri; use Hyperf\Rpc\Protocol; use Hyperf\Rpc\ProtocolManager; +use Hyperf\RpcServer\RequestDispatcher; use Hyperf\RpcServer\Server; use Hyperf\Server\ServerManager; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; use Psr\Log\LoggerInterface; use Swoole\Server as SwooleServer; @@ -39,15 +41,15 @@ class TcpServer extends Server protected $packer; public function __construct( - string $serverName, - string $coreHandler, ContainerInterface $container, - $dispatcher, - LoggerInterface $logger, - ProtocolManager $protocolManager + ProtocolManager $protocolManager, + LoggerInterface $logger ) { + $dispatcher = $container->get(RequestDispatcher::class); $protocol = new Protocol($container, $protocolManager, 'jsonrpc'); - parent::__construct($serverName, $coreHandler, $container, $protocol, $dispatcher, $logger); + + parent::__construct($container, $protocol, $dispatcher, $logger); + $this->packer = $protocol->getPacker(); $this->responseBuilder = make(ResponseBuilder::class, [ 'dataFormatter' => $protocol->getDataFormatter(), @@ -55,6 +57,11 @@ class TcpServer extends Server ]); } + protected function createCoreMiddleware(): MiddlewareInterface + { + return new CoreMiddleware($this->container, $this->protocol, $this->serverName); + } + protected function buildResponse(int $fd, SwooleServer $server): ResponseInterface { $response = new Psr7Response(); diff --git a/src/json-rpc/src/TcpServerFactory.php b/src/json-rpc/src/TcpServerFactory.php index 6a4170f5b..10c7098e0 100644 --- a/src/json-rpc/src/TcpServerFactory.php +++ b/src/json-rpc/src/TcpServerFactory.php @@ -14,18 +14,14 @@ namespace Hyperf\JsonRpc; use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\Rpc\ProtocolManager; -use Hyperf\RpcServer\RequestDispatcher; use Psr\Container\ContainerInterface; class TcpServerFactory { - protected $coreMiddleware = CoreMiddleware::class; - public function __invoke(ContainerInterface $container): TcpServer { - $dispatcher = $container->get(RequestDispatcher::class); $logger = $container->get(StdoutLoggerInterface::class); $protocolManager = $container->get(ProtocolManager::class); - return new TcpServer('jsonrpc', $this->coreMiddleware, $container, $dispatcher, $logger, $protocolManager); + return new TcpServer($container, $protocolManager, $logger); } } diff --git a/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php b/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php index 297ebed61..272127a67 100644 --- a/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php +++ b/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php @@ -24,6 +24,7 @@ use Hyperf\HttpMessage\Server\Request; use Hyperf\HttpMessage\Uri\Uri; use Hyperf\JsonRpc\CoreMiddleware; use Hyperf\JsonRpc\DataFormatter; +use Hyperf\JsonRpc\JsonRpcHttpTransporter; use Hyperf\JsonRpc\JsonRpcTransporter; use Hyperf\JsonRpc\NormalizeDataFormatter; use Hyperf\JsonRpc\PathGenerator; @@ -31,6 +32,7 @@ use Hyperf\JsonRpc\ResponseBuilder; use Hyperf\Logger\Logger; use Hyperf\Rpc\Protocol; use Hyperf\Rpc\ProtocolManager; +use Hyperf\RpcServer\RequestDispatcher; use Hyperf\RpcServer\Router\DispatcherFactory; use Hyperf\Utils\ApplicationContext; use Hyperf\Utils\Context; @@ -65,6 +67,8 @@ class AnyParamCoreMiddlewareTest extends TestCase ['value' => 1], ['value' => 2], ]); + + [$request] = $middleware->dispatch($request); Context::set(ResponseInterface::class, new Response()); $response = $middleware->process($request, $handler); @@ -119,6 +123,12 @@ class AnyParamCoreMiddlewareTest extends TestCase 'path-generator' => PathGenerator::class, 'data-formatter' => DataFormatter::class, ], + 'jsonrpc-http' => [ + 'packer' => JsonPacker::class, + 'transporter' => JsonRpcHttpTransporter::class, + 'path-generator' => PathGenerator::class, + 'data-formatter' => DataFormatter::class, + ], ], ])); $container->shouldReceive('has')->andReturn(true); @@ -146,6 +156,7 @@ class AnyParamCoreMiddlewareTest extends TestCase ->andReturnUsing(function ($class, $args) { return new ResponseBuilder(...array_values($args)); }); + $container->shouldReceive('get')->with(RequestDispatcher::class)->andReturn(new RequestDispatcher($container)); ApplicationContext::setContainer($container); return $container; diff --git a/src/rpc-server/src/Server.php b/src/rpc-server/src/Server.php index 91a762a5f..a2f861e8a 100644 --- a/src/rpc-server/src/Server.php +++ b/src/rpc-server/src/Server.php @@ -37,11 +37,6 @@ abstract class Server implements OnReceiveInterface, MiddlewareInitializerInterf */ protected $middlewares; - /** - * @var string - */ - protected $coreHandler; - /** * @var MiddlewareInterface */ @@ -78,15 +73,11 @@ abstract class Server implements OnReceiveInterface, MiddlewareInitializerInterf protected $logger; public function __construct( - string $serverName, - string $coreHandler, ContainerInterface $container, Protocol $protocol, - $dispatcher, + DispatcherInterface $dispatcher, LoggerInterface $logger ) { - $this->serverName = $serverName; - $this->coreHandler = $coreHandler; $this->container = $container; $this->protocol = $protocol; $this->dispatcher = $dispatcher; @@ -139,11 +130,7 @@ abstract class Server implements OnReceiveInterface, MiddlewareInitializerInterf $this->logger->debug(sprintf('Connect to %s:%d', $port->host, $port->port)); } - protected function createCoreMiddleware(): MiddlewareInterface - { - $coreHandler = $this->coreHandler; - return new $coreHandler($this->container, $this->protocol, $this->serverName); - } + abstract protected function createCoreMiddleware(): MiddlewareInterface; abstract protected function buildRequest(int $fd, int $fromId, string $data): ServerRequestInterface; From b89e7be0b9d81e8ce04dbcd9940b5825dc4d6c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 18:17:50 +0800 Subject: [PATCH 009/225] Fixed testing. --- src/json-rpc/tests/AnyParamCoreMiddlewareTest.php | 1 + src/json-rpc/tests/CoreMiddlewareTest.php | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php b/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php index 272127a67..bb28b4ee2 100644 --- a/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php +++ b/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php @@ -92,6 +92,7 @@ class AnyParamCoreMiddlewareTest extends TestCase ->withParsedBody([3, 0]); Context::set(ResponseInterface::class, new Response()); + [$request] = $middleware->dispatch($request); try { $response = $middleware->process($request, $handler); } catch (\Throwable $exception) { diff --git a/src/json-rpc/tests/CoreMiddlewareTest.php b/src/json-rpc/tests/CoreMiddlewareTest.php index 27e31aae2..00786da2a 100644 --- a/src/json-rpc/tests/CoreMiddlewareTest.php +++ b/src/json-rpc/tests/CoreMiddlewareTest.php @@ -64,6 +64,7 @@ class CoreMiddlewareTest extends TestCase ->withParsedBody([1, 2]); Context::set(ResponseInterface::class, new Response()); + [$request] = $middleware->dispatch($request); $response = $middleware->process($request, $handler); $this->assertEquals(200, $response->getStatusCode()); $ret = json_decode((string) $response->getBody(), true); @@ -86,6 +87,8 @@ class CoreMiddlewareTest extends TestCase ->withParsedBody([3, 0]); Context::set(ResponseInterface::class, new Response()); + [$request] = $middleware->dispatch($request); + try { $response = $middleware->process($request, $handler); } catch (\Throwable $exception) { @@ -115,6 +118,8 @@ class CoreMiddlewareTest extends TestCase ->withParsedBody([3, 0]); Context::set(ResponseInterface::class, new Response()); + [$request] = $middleware->dispatch($request); + try { $response = $middleware->process($request, $handler); } catch (\Throwable $exception) { From cbd8777003707af2d9d581bf026dfc56567fa799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 18:22:51 +0800 Subject: [PATCH 010/225] Fixed bug. --- src/rpc-server/src/Server.php | 2 ++ src/websocket-server/src/Server.php | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/rpc-server/src/Server.php b/src/rpc-server/src/Server.php index a2f861e8a..14472c3e8 100644 --- a/src/rpc-server/src/Server.php +++ b/src/rpc-server/src/Server.php @@ -107,6 +107,8 @@ abstract class Server implements OnReceiveInterface, MiddlewareInitializerInterf // $middlewares = array_merge($this->middlewares, MiddlewareManager::get()); $middlewares = $this->middlewares; + [$request] = $this->coreMiddleware->dispatch($request); + $response = $this->dispatcher->dispatch($request, $middlewares, $this->coreMiddleware); } catch (Throwable $throwable) { // Delegate the exception to exception handler. diff --git a/src/websocket-server/src/Server.php b/src/websocket-server/src/Server.php index 5e6086d87..0d75757c4 100644 --- a/src/websocket-server/src/Server.php +++ b/src/websocket-server/src/Server.php @@ -24,6 +24,7 @@ use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpServer\MiddlewareManager; +use Hyperf\HttpServer\Router\Dispatched; use Hyperf\Utils\Context; use Hyperf\WebSocketServer\Collector\FdCollector; use Hyperf\WebSocketServer\Exception\Handler\WebSocketExceptionHandler; @@ -118,7 +119,17 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On throw new WebSocketHandeShakeException('sec-websocket-key is invalid!'); } - $middlewares = array_merge($this->middlewares, MiddlewareManager::get($this->serverName, $psr7Request->getUri()->getPath(), $psr7Request->getMethod())); + /** + * @var array + * @var ServerRequestInterface $psr7Request + * @var Dispatched $dispatched + */ + [$psr7Request, $dispatched] = $this->coreMiddleware->dispatch($psr7Request); + $middlewares = $this->middlewares; + if ($dispatched->isFind()) { + $registedMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod()); + $middlewares = array_merge($middlewares, $registedMiddlewares); + } $psr7Response = $this->dispatcher->dispatch($psr7Request, $middlewares, $this->coreMiddleware); From 445370c65c2c74a0fc348ee7a40f2ccf817ae900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 18:52:11 +0800 Subject: [PATCH 011/225] Added coremiddleware testing. --- src/http-server/tests/CoreMiddlewareTest.php | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/http-server/tests/CoreMiddlewareTest.php b/src/http-server/tests/CoreMiddlewareTest.php index 2c2d97cf2..c5eb0762c 100644 --- a/src/http-server/tests/CoreMiddlewareTest.php +++ b/src/http-server/tests/CoreMiddlewareTest.php @@ -15,8 +15,12 @@ namespace HyperfTest\HttpServer; use Hyperf\Contract\NormalizerInterface; use Hyperf\Di\MethodDefinitionCollector; use Hyperf\Di\MethodDefinitionCollectorInterface; +use Hyperf\HttpMessage\Server\Request; +use Hyperf\HttpMessage\Uri\Uri; use Hyperf\HttpServer\CoreMiddleware; +use Hyperf\HttpServer\Router\Dispatched; use Hyperf\HttpServer\Router\DispatcherFactory; +use Hyperf\HttpServer\Router\Handler; use Hyperf\Utils\Contracts\Arrayable; use Hyperf\Utils\Contracts\Jsonable; use Hyperf\Utils\Serializer\SimpleNormalizer; @@ -99,6 +103,44 @@ class CoreMiddlewareTest extends TestCase $this->assertSame('text/plain', $response->getHeaderLine('content-type')); } + public function testDispatch() + { + $container = $this->getContainer(); + + $router = $container->get(DispatcherFactory::class)->getRouter('http'); + $router->addRoute('GET', '/user', 'UserController::index'); + $router->addRoute('GET', '/user/{id:\d+}', 'UserController::info'); + + $middleware = new CoreMiddleware($container, 'http'); + + $request = new Request('GET', new Uri('/user')); + [$request, $dispatched] = $middleware->dispatch($request); + $this->assertInstanceOf(Request::class, $request); + $this->assertInstanceOf(Dispatched::class, $dispatched); + $this->assertInstanceOf(Handler::class, $dispatched->handler); + $this->assertSame($dispatched, $request->getAttribute(Dispatched::class)); + $this->assertSame('/user', $dispatched->handler->route); + $this->assertSame('UserController::index', $dispatched->handler->callback); + $this->assertTrue($dispatched->isFind()); + + $request = new Request('GET', new Uri('/user/123')); + [$request, $dispatched] = $middleware->dispatch($request); + $this->assertInstanceOf(Request::class, $request); + $this->assertInstanceOf(Dispatched::class, $dispatched); + $this->assertInstanceOf(Handler::class, $dispatched->handler); + $this->assertSame($dispatched, $request->getAttribute(Dispatched::class)); + $this->assertSame('/user/{id:\d+}', $dispatched->handler->route); + $this->assertSame('UserController::info', $dispatched->handler->callback); + $this->assertTrue($dispatched->isFind()); + + $request = new Request('GET', new Uri('/users')); + [$request, $dispatched] = $middleware->dispatch($request); + $this->assertInstanceOf(Request::class, $request); + $this->assertInstanceOf(Dispatched::class, $dispatched); + $this->assertSame($dispatched, $request->getAttribute(Dispatched::class)); + $this->assertFalse($dispatched->isFind()); + } + protected function getContainer() { $container = Mockery::mock(ContainerInterface::class); From 136e17df10f9e8c37e938dbfe07bd8b2cba1ec5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 14 Aug 2019 19:03:18 +0800 Subject: [PATCH 012/225] Fixed grpc-server. --- src/grpc-server/src/CoreMiddleware.php | 24 +++++++++++------------- src/grpc-server/src/Server.php | 8 -------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/grpc-server/src/CoreMiddleware.php b/src/grpc-server/src/CoreMiddleware.php index 922c6b048..03a0d8509 100644 --- a/src/grpc-server/src/CoreMiddleware.php +++ b/src/grpc-server/src/CoreMiddleware.php @@ -20,6 +20,8 @@ use Hyperf\Di\ReflectionManager; use Hyperf\Grpc\Parser; use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\HttpServer\CoreMiddleware as HttpCoreMiddleware; +use Hyperf\HttpServer\Router\Dispatched; +use Hyperf\Server\Exception\ServerException; use Hyperf\Utils\Context; use Psr\Container\ContainerInterface; use Psr\Http\Message\RequestInterface; @@ -45,26 +47,22 @@ class CoreMiddleware extends HttpCoreMiddleware */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { - /** @var ResponseInterface $response */ - $uri = $request->getUri(); + /** @var Dispatched $dispatched */ + $dispatched = $request->getAttribute(Dispatched::class); - /** - * @var array - * Returns array with one of the following formats: - * [self::NOT_FOUND] - * [self::METHOD_NOT_ALLOWED, ['GET', 'OTHER_ALLOWED_METHODS']] - * [self::FOUND, $handler, ['varName' => 'value', ...]] - */ - $routes = $this->dispatcher->dispatch($request->getMethod(), $uri->getPath()); - switch ($routes[0]) { + if (! $dispatched instanceof Dispatched) { + throw new ServerException('Dispatch failed.'); + } + + switch ($dispatched->status) { case Dispatcher::FOUND: - [$controller, $action] = $this->prepareHandler($routes[1]); + [$controller, $action] = $this->prepareHandler($dispatched->handler->callback); $controllerInstance = $this->container->get($controller); if (! method_exists($controller, $action)) { $grpcMessage = 'Action not exist.'; return $this->handleResponse(null, 500, '500', $grpcMessage); } - $parameters = $this->parseParameters($controller, $action, $routes[2]); + $parameters = $this->parseParameters($controller, $action, $dispatched->params); $result = $controllerInstance->{$action}(...$parameters); if (! $result instanceof Message) { $grpcMessage = 'The result is not a valid message.'; diff --git a/src/grpc-server/src/Server.php b/src/grpc-server/src/Server.php index 067f0eedd..3621e6beb 100644 --- a/src/grpc-server/src/Server.php +++ b/src/grpc-server/src/Server.php @@ -13,19 +13,11 @@ declare(strict_types=1); namespace Hyperf\GrpcServer; use Hyperf\Contract\ConfigInterface; -use Hyperf\Dispatcher\HttpDispatcher; use Hyperf\GrpcServer\Exception\Handler\GrpcExceptionHandler; use Hyperf\HttpServer\Server as HttpServer; -use Psr\Container\ContainerInterface; class Server extends HttpServer { - public function __construct(ContainerInterface $container) - { - $this->container = $container; - $this->dispatcher = $container->get(HttpDispatcher::class); - } - public function initCoreMiddleware(string $serverName): void { $this->serverName = $serverName; From f3451712a66c32acb78741cb91d429f20b676c73 Mon Sep 17 00:00:00 2001 From: Jeroen Herczeg Date: Thu, 15 Aug 2019 01:13:21 +0200 Subject: [PATCH 013/225] Update README.md Hi, Thank you for your hard work! I'm interested in contributing, primarily translating the documentation in English. Is this something that you would need? Kind regards, Jeroen --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c4d62222b..2a3fb4102 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ In addition to providing `MySQL coroutine client` and `Redis coroutine client`, # Original intention -Although there are many new PHP frameworks have been appeared, but we still has not seen a perfect framework which has the coexistence of elegant design and ultra-high performance, nor would we find a framework that really paves the way for PHP microservices. For the original intention of Hyperf and its team members, we will continue to invest to it, and you are welcome to join us to participate in open source construction. +Although many new PHP frameworks have appeared, we still haven't seen a comprehensive framework, which introduces an elegant design and ultra-high performance, suitable for PHP microservices. For the original intention of Hyperf and its team members, we will continue to invest to it, and you are welcome to join us to participate in open source construction. # Design concept From 647a9bb99030d32273ba9be4c71ecf6e32164a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 10:36:12 +0800 Subject: [PATCH 014/225] Deprecated some class. --- src/http-server/src/ServerFactory.php | 26 +++++++++++++++++++++++++ src/json-rpc/src/HttpServerFactory.php | 27 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/http-server/src/ServerFactory.php create mode 100644 src/json-rpc/src/HttpServerFactory.php diff --git a/src/http-server/src/ServerFactory.php b/src/http-server/src/ServerFactory.php new file mode 100644 index 000000000..0cb2631da --- /dev/null +++ b/src/http-server/src/ServerFactory.php @@ -0,0 +1,26 @@ +get(ProtocolManager::class)); + } +} From a1e10d04e2a271deb1a8b9baffd124644feb9da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 10:58:53 +0800 Subject: [PATCH 015/225] Update websocket server. --- src/websocket-server/src/CoreMiddleware.php | 23 ++++++++----------- .../Handler/WebSocketExceptionHandler.php | 2 +- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/websocket-server/src/CoreMiddleware.php b/src/websocket-server/src/CoreMiddleware.php index c2a46265b..7a88420d1 100644 --- a/src/websocket-server/src/CoreMiddleware.php +++ b/src/websocket-server/src/CoreMiddleware.php @@ -15,6 +15,7 @@ namespace Hyperf\WebSocketServer; use FastRoute\Dispatcher; use Hyperf\HttpServer\CoreMiddleware as HttpCoreMiddleware; use Hyperf\HttpServer\Router\Dispatched; +use Hyperf\Server\Exception\ServerException; use Hyperf\Utils\Context; use Hyperf\Utils\Contracts\Arrayable; use Hyperf\WebSocketServer\Exception\WebSocketHandeShakeException; @@ -30,26 +31,22 @@ class CoreMiddleware extends HttpCoreMiddleware */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { - /** @var ResponseInterface $response */ - $uri = $request->getUri(); - /** - * @var array - * Returns array with one of the following formats: - * [self::NOT_FOUND] - * [self::METHOD_NOT_ALLOWED, ['GET', 'OTHER_ALLOWED_METHODS']] - * [self::FOUND, $handler, ['varName' => 'value', ...]] - */ - $routes = $this->dispatcher->dispatch($request->getMethod(), $uri->getPath()); + /** @var Dispatched $dispatched */ + $dispatched = $request->getAttribute(Dispatched::class); - switch ($routes[0]) { + if (! $dispatched instanceof Dispatched) { + throw new ServerException('Dispatch failed.'); + } + + switch ($dispatched->status) { case Dispatcher::NOT_FOUND: $response = $this->handleNotFound($request); break; case Dispatcher::METHOD_NOT_ALLOWED: - $response = $this->handleMethodNotAllowed($routes, $request); + $response = $this->handleMethodNotAllowed($dispatched->params, $request); break; case Dispatcher::FOUND: - $response = $this->handleFound($routes, $request); + $response = $this->handleFound($dispatched, $request); break; } if (! $response instanceof ResponseInterface) { diff --git a/src/websocket-server/src/Exception/Handler/WebSocketExceptionHandler.php b/src/websocket-server/src/Exception/Handler/WebSocketExceptionHandler.php index 461e99431..903aca9c1 100644 --- a/src/websocket-server/src/Exception/Handler/WebSocketExceptionHandler.php +++ b/src/websocket-server/src/Exception/Handler/WebSocketExceptionHandler.php @@ -40,7 +40,7 @@ class WebSocketExceptionHandler extends ExceptionHandler public function handle(Throwable $throwable, ResponseInterface $response) { $this->logger->warning($this->formatter->format($throwable)); - $stream = new SwooleStream((string) $exception->getMessage()); + $stream = new SwooleStream((string) $throwable->getMessage()); return $response->withBody($stream); } From e3d13967a539548a96184716be3812ec6b693071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 11:49:23 +0800 Subject: [PATCH 016/225] Added CoreMiddlewareInterface who extends MiddlewareInterface. --- src/grpc-server/src/CoreMiddleware.php | 2 +- .../src/Contract/CoreMiddlewareInterface.php | 31 +++++++++++++++++++ src/http-server/src/CoreMiddleware.php | 6 ++-- src/http-server/src/Server.php | 6 ++-- src/json-rpc/src/HttpCoreMiddleware.php | 3 -- src/json-rpc/src/HttpServer.php | 4 +-- src/json-rpc/src/TcpServer.php | 4 +-- src/rpc-server/src/Server.php | 5 +-- src/websocket-server/src/CoreMiddleware.php | 2 +- src/websocket-server/src/Server.php | 3 +- 10 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 src/http-server/src/Contract/CoreMiddlewareInterface.php diff --git a/src/grpc-server/src/CoreMiddleware.php b/src/grpc-server/src/CoreMiddleware.php index 03a0d8509..0a6c513d8 100644 --- a/src/grpc-server/src/CoreMiddleware.php +++ b/src/grpc-server/src/CoreMiddleware.php @@ -51,7 +51,7 @@ class CoreMiddleware extends HttpCoreMiddleware $dispatched = $request->getAttribute(Dispatched::class); if (! $dispatched instanceof Dispatched) { - throw new ServerException('Dispatch failed.'); + throw new ServerException('The object is not instanceof `HyperfHttpServerRouterDispatched`.'); } switch ($dispatched->status) { diff --git a/src/http-server/src/Contract/CoreMiddlewareInterface.php b/src/http-server/src/Contract/CoreMiddlewareInterface.php new file mode 100644 index 000000000..fd7372554 --- /dev/null +++ b/src/http-server/src/Contract/CoreMiddlewareInterface.php @@ -0,0 +1,31 @@ +getAttribute(Dispatched::class); if (! $dispatched instanceof Dispatched) { - throw new ServerException('Dispatch failed.'); + throw new ServerException('The object is not instanceof `HyperfHttpServerRouterDispatched`.'); } switch ($dispatched->status) { diff --git a/src/http-server/src/Server.php b/src/http-server/src/Server.php index b3eb238a7..bd05e0ec0 100644 --- a/src/http-server/src/Server.php +++ b/src/http-server/src/Server.php @@ -20,6 +20,7 @@ use Hyperf\Dispatcher\HttpDispatcher; use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; +use Hyperf\HttpServer\Contract\CoreMiddlewareInterface; use Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler; use Hyperf\HttpServer\Router\Dispatched; use Hyperf\HttpServer\Router\DispatcherFactory; @@ -28,7 +29,6 @@ use Hyperf\Utils\Context; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\MiddlewareInterface; use Swoole\Http\Request as SwooleRequest; use Swoole\Http\Response as SwooleResponse; use Throwable; @@ -41,7 +41,7 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface protected $middlewares; /** - * @var MiddlewareInterface + * @var CoreMiddlewareInterface */ protected $coreMiddleware; @@ -145,7 +145,7 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface ]; } - protected function createCoreMiddleware(): MiddlewareInterface + protected function createCoreMiddleware(): CoreMiddlewareInterface { return new CoreMiddleware($this->container, $this->serverName); } diff --git a/src/json-rpc/src/HttpCoreMiddleware.php b/src/json-rpc/src/HttpCoreMiddleware.php index ae49a7c13..809d21c1f 100644 --- a/src/json-rpc/src/HttpCoreMiddleware.php +++ b/src/json-rpc/src/HttpCoreMiddleware.php @@ -14,9 +14,6 @@ namespace Hyperf\JsonRpc; use Psr\Http\Message\ServerRequestInterface; -/** - * {@inheritdoc} - */ class HttpCoreMiddleware extends CoreMiddleware { protected function handleNotFound(ServerRequestInterface $request) diff --git a/src/json-rpc/src/HttpServer.php b/src/json-rpc/src/HttpServer.php index bc57545b7..b51ad4caa 100644 --- a/src/json-rpc/src/HttpServer.php +++ b/src/json-rpc/src/HttpServer.php @@ -14,6 +14,7 @@ namespace Hyperf\JsonRpc; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; +use Hyperf\HttpServer\Contract\CoreMiddlewareInterface; use Hyperf\HttpServer\Server; use Hyperf\JsonRpc\Exception\Handler\HttpExceptionHandler; use Hyperf\Rpc\Protocol; @@ -24,7 +25,6 @@ use Psr\Container\ContainerInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\MiddlewareInterface; use Swoole\Http\Request as SwooleRequest; use Swoole\Http\Response as SwooleResponse; @@ -64,7 +64,7 @@ class HttpServer extends Server ]; } - protected function createCoreMiddleware(): MiddlewareInterface + protected function createCoreMiddleware(): CoreMiddlewareInterface { return new HttpCoreMiddleware($this->container, $this->protocol, $this->serverName); } diff --git a/src/json-rpc/src/TcpServer.php b/src/json-rpc/src/TcpServer.php index 7c07ffa85..e23b7865d 100644 --- a/src/json-rpc/src/TcpServer.php +++ b/src/json-rpc/src/TcpServer.php @@ -16,6 +16,7 @@ use Hyperf\Contract\PackerInterface; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpMessage\Uri\Uri; +use Hyperf\HttpServer\Contract\CoreMiddlewareInterface; use Hyperf\Rpc\Protocol; use Hyperf\Rpc\ProtocolManager; use Hyperf\RpcServer\RequestDispatcher; @@ -24,7 +25,6 @@ use Hyperf\Server\ServerManager; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\MiddlewareInterface; use Psr\Log\LoggerInterface; use Swoole\Server as SwooleServer; @@ -57,7 +57,7 @@ class TcpServer extends Server ]); } - protected function createCoreMiddleware(): MiddlewareInterface + protected function createCoreMiddleware(): CoreMiddlewareInterface { return new CoreMiddleware($this->container, $this->protocol, $this->serverName); } diff --git a/src/rpc-server/src/Server.php b/src/rpc-server/src/Server.php index 14472c3e8..bab6dd6e0 100644 --- a/src/rpc-server/src/Server.php +++ b/src/rpc-server/src/Server.php @@ -18,6 +18,7 @@ use Hyperf\Contract\MiddlewareInitializerInterface; use Hyperf\Contract\OnReceiveInterface; use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Stream\SwooleStream; +use Hyperf\HttpServer\Contract\CoreMiddlewareInterface; use Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler; use Hyperf\Rpc\Protocol; use Hyperf\Server\ServerManager; @@ -38,7 +39,7 @@ abstract class Server implements OnReceiveInterface, MiddlewareInitializerInterf protected $middlewares; /** - * @var MiddlewareInterface + * @var CoreMiddlewareInterface */ protected $coreMiddleware; @@ -132,7 +133,7 @@ abstract class Server implements OnReceiveInterface, MiddlewareInitializerInterf $this->logger->debug(sprintf('Connect to %s:%d', $port->host, $port->port)); } - abstract protected function createCoreMiddleware(): MiddlewareInterface; + abstract protected function createCoreMiddleware(): CoreMiddlewareInterface; abstract protected function buildRequest(int $fd, int $fromId, string $data): ServerRequestInterface; diff --git a/src/websocket-server/src/CoreMiddleware.php b/src/websocket-server/src/CoreMiddleware.php index 7a88420d1..03cc318c6 100644 --- a/src/websocket-server/src/CoreMiddleware.php +++ b/src/websocket-server/src/CoreMiddleware.php @@ -35,7 +35,7 @@ class CoreMiddleware extends HttpCoreMiddleware $dispatched = $request->getAttribute(Dispatched::class); if (! $dispatched instanceof Dispatched) { - throw new ServerException('Dispatch failed.'); + throw new ServerException('The object is not instanceof `HyperfHttpServerRouterDispatched`.'); } switch ($dispatched->status) { diff --git a/src/websocket-server/src/Server.php b/src/websocket-server/src/Server.php index 0d75757c4..41555d677 100644 --- a/src/websocket-server/src/Server.php +++ b/src/websocket-server/src/Server.php @@ -23,6 +23,7 @@ use Hyperf\Dispatcher\HttpDispatcher; use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; +use Hyperf\HttpServer\Contract\CoreMiddlewareInterface; use Hyperf\HttpServer\MiddlewareManager; use Hyperf\HttpServer\Router\Dispatched; use Hyperf\Utils\Context; @@ -51,7 +52,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On protected $dispatcher; /** - * @var CoreMiddleware + * @var CoreMiddlewareInterface */ protected $coreMiddleware; From 7804eb308c9529c0f41dc75401b3d834eee3b65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 16:29:49 +0800 Subject: [PATCH 017/225] Renamed master(1.1) --- bin/release.sh | 2 +- bin/split.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/release.sh b/bin/release.sh index cf169feed..1c7cf2d09 100755 --- a/bin/release.sh +++ b/bin/release.sh @@ -9,7 +9,7 @@ then fi NOW=$(date +%s) -CURRENT_BRANCH="1.1" +CURRENT_BRANCH="master" VERSION=$1 BASEPATH=$(cd `dirname $0`; cd ../src/; pwd) diff --git a/bin/split.sh b/bin/split.sh index fbfa0de9b..68cbc71b1 100755 --- a/bin/split.sh +++ b/bin/split.sh @@ -3,7 +3,7 @@ set -e set -x -CURRENT_BRANCH="1.1" +CURRENT_BRANCH="master" BASEPATH=$(cd `dirname $0`; cd ../src/; pwd) REPOS=$@ From 0c7dbf12144e8a47f6647e83a885f4b1392b30a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 16:44:53 +0800 Subject: [PATCH 018/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 563cba290..6591611fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v1.0.12 - TBD +# v1.1.0 - TBD # v1.0.11 - 2019-08-15 From 9a9f87f18dacc4ebd03be79bfd041fb6dacd84be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 16:48:13 +0800 Subject: [PATCH 019/225] Update branch-alias of snowflake. --- src/snowflake/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snowflake/composer.json b/src/snowflake/composer.json index 708507e71..b23fc604f 100644 --- a/src/snowflake/composer.json +++ b/src/snowflake/composer.json @@ -36,7 +36,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" }, "hyperf": { "config": "Hyperf\\Snowflake\\ConfigProvider" From 75b28488274bf9891bb49242660b8aa2b6d52532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 17:24:26 +0800 Subject: [PATCH 020/225] Added Annotation AsyncQueue. --- src/async-queue/src/Annotation/AsyncQueue.php | 26 +++++++ src/async-queue/src/AnnotationJob.php | 42 +++++++++++ .../src/Aspect/AsyncQueueAspect.php | 70 +++++++++++++++++++ src/async-queue/src/Driver/Driver.php | 3 + .../src/Driver/DriverInterface.php | 6 -- src/async-queue/src/Driver/RedisDriver.php | 14 ---- src/async-queue/src/Environment.php | 29 ++++++++ 7 files changed, 170 insertions(+), 20 deletions(-) create mode 100644 src/async-queue/src/Annotation/AsyncQueue.php create mode 100644 src/async-queue/src/AnnotationJob.php create mode 100644 src/async-queue/src/Aspect/AsyncQueueAspect.php create mode 100644 src/async-queue/src/Environment.php diff --git a/src/async-queue/src/Annotation/AsyncQueue.php b/src/async-queue/src/Annotation/AsyncQueue.php new file mode 100644 index 000000000..22cc7c5a6 --- /dev/null +++ b/src/async-queue/src/Annotation/AsyncQueue.php @@ -0,0 +1,26 @@ +class = $class; + $this->method = $method; + $this->params = $params; + } + + public function handle() + { + } +} diff --git a/src/async-queue/src/Aspect/AsyncQueueAspect.php b/src/async-queue/src/Aspect/AsyncQueueAspect.php new file mode 100644 index 000000000..0927a4e6d --- /dev/null +++ b/src/async-queue/src/Aspect/AsyncQueueAspect.php @@ -0,0 +1,70 @@ +container = $container; + } + + public function process(ProceedingJoinPoint $proceedingJoinPoint) + { + $env = $this->container->get(Environment::class); + if ($env->isAsyncQueue()) { + $proceedingJoinPoint->process(); + return; + } + + $class = $proceedingJoinPoint->className; + $method = $proceedingJoinPoint->methodName; + $arguments = $proceedingJoinPoint->getArguments(); + $pool = 'default'; + $delay = 0; + + $metadata = $proceedingJoinPoint->getAnnotationMetadata(); + /** @var AsyncQueue $annotation */ + $annotation = $metadata->method[AsyncQueue::class] ?? $metadata->class[AsyncQueue::class] ?? null; + if ($annotation instanceof AsyncQueue) { + $pool = $annotation->pool; + $delay = $annotation->delay; + } + + $factory = $this->container->get(DriverFactory::class); + $driver = $factory->get($pool); + + $driver->push(new AnnotationJob($class, $method, $arguments), $delay); + } +} diff --git a/src/async-queue/src/Driver/Driver.php b/src/async-queue/src/Driver/Driver.php index 0f32b46c9..bbccffc11 100644 --- a/src/async-queue/src/Driver/Driver.php +++ b/src/async-queue/src/Driver/Driver.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Hyperf\AsyncQueue\Driver; +use Hyperf\AsyncQueue\Environment; use Hyperf\AsyncQueue\Event\AfterHandle; use Hyperf\AsyncQueue\Event\BeforeHandle; use Hyperf\AsyncQueue\Event\FailedHandle; @@ -53,6 +54,8 @@ abstract class Driver implements DriverInterface public function consume(): void { + $this->container->get(Environment::class)->setAsyncQueue(true); + while (true) { [$data, $message] = $this->pop(); diff --git a/src/async-queue/src/Driver/DriverInterface.php b/src/async-queue/src/Driver/DriverInterface.php index 70647c144..d309f64ed 100644 --- a/src/async-queue/src/Driver/DriverInterface.php +++ b/src/async-queue/src/Driver/DriverInterface.php @@ -21,12 +21,6 @@ interface DriverInterface */ public function push(JobInterface $job, int $delay = 0): bool; - /** - * Push a delay job to queue. - * @deprecated v1.1 - */ - public function delay(JobInterface $job, int $delay = 0): bool; - /** * Delete a delay job to queue. */ diff --git a/src/async-queue/src/Driver/RedisDriver.php b/src/async-queue/src/Driver/RedisDriver.php index 7d324d172..f63de48e0 100644 --- a/src/async-queue/src/Driver/RedisDriver.php +++ b/src/async-queue/src/Driver/RedisDriver.php @@ -74,20 +74,6 @@ class RedisDriver extends Driver return $this->redis->zAdd($this->channel->getDelayed(), time() + $delay, $data) > 0; } - /** - * @deprecated v1.1 - */ - public function delay(JobInterface $job, int $delay = 0): bool - { - if ($delay === 0) { - return $this->push($job); - } - - $message = new Message($job); - $data = $this->packer->pack($message); - return $this->redis->zAdd($this->channel->getDelayed(), time() + $delay, $data) > 0; - } - public function delete(JobInterface $job): bool { $message = new Message($job); diff --git a/src/async-queue/src/Environment.php b/src/async-queue/src/Environment.php new file mode 100644 index 000000000..a6bb37974 --- /dev/null +++ b/src/async-queue/src/Environment.php @@ -0,0 +1,29 @@ +asyncQueue; + } + + public function setAsyncQueue(bool $asyncQueue): self + { + $this->asyncQueue = $asyncQueue; + return $this; + } +} From 6720367e7fc850dfed04594d9ba28c0297efe9f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 17:25:13 +0800 Subject: [PATCH 021/225] Delete ServerFactory.php --- src/grpc-server/src/ServerFactory.php | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 src/grpc-server/src/ServerFactory.php diff --git a/src/grpc-server/src/ServerFactory.php b/src/grpc-server/src/ServerFactory.php deleted file mode 100644 index e7a963d51..000000000 --- a/src/grpc-server/src/ServerFactory.php +++ /dev/null @@ -1,26 +0,0 @@ - Date: Thu, 15 Aug 2019 17:35:56 +0800 Subject: [PATCH 022/225] Update AnnotationJob.php --- src/async-queue/src/AnnotationJob.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/async-queue/src/AnnotationJob.php b/src/async-queue/src/AnnotationJob.php index 5bfdecd2a..1f046ab5d 100644 --- a/src/async-queue/src/AnnotationJob.php +++ b/src/async-queue/src/AnnotationJob.php @@ -12,6 +12,8 @@ declare(strict_types=1); namespace Hyperf\AsyncQueue; +use Hyperf\Utils\ApplicationContext; + class AnnotationJob extends Job { /** @@ -38,5 +40,10 @@ class AnnotationJob extends Job public function handle() { + $container = ApplicationContext::getContainer(); + + $class = $container->get($this->class); + + $class->{$this->method}(...$this->params); } } From e35e8cad8710229ed7cdaf3dc5ab9c78807effcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 17:48:11 +0800 Subject: [PATCH 023/225] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6591611fa..c87973c4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # v1.1.0 - TBD +## Added + +- [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueue. + # v1.0.11 - 2019-08-15 ## Added From 6a8275074a293fa90c7fe9ba44b9a95eb3450940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 17:51:12 +0800 Subject: [PATCH 024/225] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6591611fa..5eb69a336 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # v1.1.0 - TBD +## Added + +- [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Optimized server and Fixed middleware that user defined does not works. + # v1.0.11 - 2019-08-15 ## Added From 5439e977fed3c29453ae5e983ef4dc2708c6992f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 18:04:45 +0800 Subject: [PATCH 025/225] Renamed Annotation. --- .../{AsyncQueue.php => AsyncQueueMessage.php} | 2 +- src/async-queue/src/AnnotationJob.php | 18 ++++++++++++++++-- .../src/Aspect/AsyncQueueAspect.php | 10 +++++----- 3 files changed, 22 insertions(+), 8 deletions(-) rename src/async-queue/src/Annotation/{AsyncQueue.php => AsyncQueueMessage.php} (89%) diff --git a/src/async-queue/src/Annotation/AsyncQueue.php b/src/async-queue/src/Annotation/AsyncQueueMessage.php similarity index 89% rename from src/async-queue/src/Annotation/AsyncQueue.php rename to src/async-queue/src/Annotation/AsyncQueueMessage.php index 22cc7c5a6..a5703d6d0 100644 --- a/src/async-queue/src/Annotation/AsyncQueue.php +++ b/src/async-queue/src/Annotation/AsyncQueueMessage.php @@ -18,7 +18,7 @@ use Hyperf\Di\Annotation\AbstractAnnotation; * @Annotation * @Target({"CLASS", "METHOD"}) */ -class AsyncQueue extends AbstractAnnotation +class AsyncQueueMessage extends AbstractAnnotation { public $pool = 'default'; diff --git a/src/async-queue/src/AnnotationJob.php b/src/async-queue/src/AnnotationJob.php index 1f046ab5d..9a2d83638 100644 --- a/src/async-queue/src/AnnotationJob.php +++ b/src/async-queue/src/AnnotationJob.php @@ -12,6 +12,8 @@ declare(strict_types=1); namespace Hyperf\AsyncQueue; +use Hyperf\Contract\CompressInterface; +use Hyperf\Contract\UnCompressInterface; use Hyperf\Utils\ApplicationContext; class AnnotationJob extends Job @@ -29,13 +31,18 @@ class AnnotationJob extends Job /** * @var array */ - public $params; + public $params = []; public function __construct(string $class, string $method, array $params) { $this->class = $class; $this->method = $method; - $this->params = $params; + foreach ($params as $key => $value) { + if ($value instanceof CompressInterface) { + $value = $value->compress(); + } + $this->params[$key] = $value; + } } public function handle() @@ -44,6 +51,13 @@ class AnnotationJob extends Job $class = $container->get($this->class); + $params = []; + foreach ($this->params as $key => $value) { + if ($value instanceof UnCompressInterface) { + $value = $value->uncompress(); + } + $params[$key] = $value; + } $class->{$this->method}(...$this->params); } } diff --git a/src/async-queue/src/Aspect/AsyncQueueAspect.php b/src/async-queue/src/Aspect/AsyncQueueAspect.php index 0927a4e6d..2f4137414 100644 --- a/src/async-queue/src/Aspect/AsyncQueueAspect.php +++ b/src/async-queue/src/Aspect/AsyncQueueAspect.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Hyperf\AsyncQueue\Aspect; -use Hyperf\AsyncQueue\Annotation\AsyncQueue; +use Hyperf\AsyncQueue\Annotation\AsyncQueueMessage; use Hyperf\AsyncQueue\AnnotationJob; use Hyperf\AsyncQueue\Driver\DriverFactory; use Hyperf\AsyncQueue\Environment; @@ -27,7 +27,7 @@ use Psr\Container\ContainerInterface; class AsyncQueueAspect extends AbstractAspect { public $annotations = [ - AsyncQueue::class, + AsyncQueueMessage::class, ]; /** @@ -55,9 +55,9 @@ class AsyncQueueAspect extends AbstractAspect $delay = 0; $metadata = $proceedingJoinPoint->getAnnotationMetadata(); - /** @var AsyncQueue $annotation */ - $annotation = $metadata->method[AsyncQueue::class] ?? $metadata->class[AsyncQueue::class] ?? null; - if ($annotation instanceof AsyncQueue) { + /** @var AsyncQueueMessage $annotation */ + $annotation = $metadata->method[AsyncQueueMessage::class] ?? $metadata->class[AsyncQueueMessage::class] ?? null; + if ($annotation instanceof AsyncQueueMessage) { $pool = $annotation->pool; $delay = $annotation->delay; } From 04517d4a45feb65a61d258f784cf6d03d8683ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 15 Aug 2019 18:13:57 +0800 Subject: [PATCH 026/225] Fixed bug. --- src/async-queue/src/AnnotationJob.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/async-queue/src/AnnotationJob.php b/src/async-queue/src/AnnotationJob.php index 9a2d83638..0ed55ee28 100644 --- a/src/async-queue/src/AnnotationJob.php +++ b/src/async-queue/src/AnnotationJob.php @@ -58,6 +58,6 @@ class AnnotationJob extends Job } $params[$key] = $value; } - $class->{$this->method}(...$this->params); + $class->{$this->method}(...$params); } } From b7a866d1774f0662fea0ea0a513ace4a439b162f Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Thu, 15 Aug 2019 18:25:07 +0800 Subject: [PATCH 027/225] Rename isFind to isFound --- src/http-server/src/Router/Dispatched.php | 4 ++-- src/http-server/src/Server.php | 2 +- src/http-server/tests/CoreMiddlewareTest.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/http-server/src/Router/Dispatched.php b/src/http-server/src/Router/Dispatched.php index 85b02de91..335f071e1 100644 --- a/src/http-server/src/Router/Dispatched.php +++ b/src/http-server/src/Router/Dispatched.php @@ -54,8 +54,8 @@ class Dispatched } } - public function isFind() + public function isFound(): bool { - return $this->status == Dispatcher::FOUND; + return $this->status === Dispatcher::FOUND; } } diff --git a/src/http-server/src/Server.php b/src/http-server/src/Server.php index bd05e0ec0..b90c91dfe 100644 --- a/src/http-server/src/Server.php +++ b/src/http-server/src/Server.php @@ -99,7 +99,7 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface */ [$psr7Request, $dispatched] = $this->coreMiddleware->dispatch($psr7Request); $middlewares = $this->middlewares; - if ($dispatched->isFind()) { + if ($dispatched->isFound()) { $registedMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod()); $middlewares = array_merge($middlewares, $registedMiddlewares); } diff --git a/src/http-server/tests/CoreMiddlewareTest.php b/src/http-server/tests/CoreMiddlewareTest.php index c5eb0762c..ad583fd64 100644 --- a/src/http-server/tests/CoreMiddlewareTest.php +++ b/src/http-server/tests/CoreMiddlewareTest.php @@ -121,7 +121,7 @@ class CoreMiddlewareTest extends TestCase $this->assertSame($dispatched, $request->getAttribute(Dispatched::class)); $this->assertSame('/user', $dispatched->handler->route); $this->assertSame('UserController::index', $dispatched->handler->callback); - $this->assertTrue($dispatched->isFind()); + $this->assertTrue($dispatched->isFound()); $request = new Request('GET', new Uri('/user/123')); [$request, $dispatched] = $middleware->dispatch($request); @@ -131,14 +131,14 @@ class CoreMiddlewareTest extends TestCase $this->assertSame($dispatched, $request->getAttribute(Dispatched::class)); $this->assertSame('/user/{id:\d+}', $dispatched->handler->route); $this->assertSame('UserController::info', $dispatched->handler->callback); - $this->assertTrue($dispatched->isFind()); + $this->assertTrue($dispatched->isFound()); $request = new Request('GET', new Uri('/users')); [$request, $dispatched] = $middleware->dispatch($request); $this->assertInstanceOf(Request::class, $request); $this->assertInstanceOf(Dispatched::class, $dispatched); $this->assertSame($dispatched, $request->getAttribute(Dispatched::class)); - $this->assertFalse($dispatched->isFind()); + $this->assertFalse($dispatched->isFound()); } protected function getContainer() From 57cd467045cb3baeb89d9c81921853aae3fdee29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Fri, 16 Aug 2019 01:25:51 +0800 Subject: [PATCH 028/225] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a3fb4102..546ea55b3 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ In addition to providing `MySQL coroutine client` and `Redis coroutine client`, # Original intention -Although many new PHP frameworks have appeared, we still haven't seen a comprehensive framework, which introduces an elegant design and ultra-high performance, suitable for PHP microservices. For the original intention of Hyperf and its team members, we will continue to invest to it, and you are welcome to join us to participate in open source construction. +Although many new PHP frameworks have appeared, we still haven't seen a comprehensive framework, which introduces an elegant design and ultra-high performance, suitable for PHP microservices and as an evangelist of PHP microservices. For the original intention of Hyperf and its team members, we will continue to invest to it, and you are welcome to join us to participate in open source construction. # Design concept From a42b4baf13ccec6137ad3a9ae924480a3281eed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Fri, 16 Aug 2019 01:27:31 +0800 Subject: [PATCH 029/225] Update AsyncQueueMessage.php --- src/async-queue/src/Annotation/AsyncQueueMessage.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/async-queue/src/Annotation/AsyncQueueMessage.php b/src/async-queue/src/Annotation/AsyncQueueMessage.php index a5703d6d0..681c0f293 100644 --- a/src/async-queue/src/Annotation/AsyncQueueMessage.php +++ b/src/async-queue/src/Annotation/AsyncQueueMessage.php @@ -20,7 +20,13 @@ use Hyperf\Di\Annotation\AbstractAnnotation; */ class AsyncQueueMessage extends AbstractAnnotation { + /** + * @var string + */ public $pool = 'default'; + /** + * @var int + */ public $delay = 0; } From fdd32ce244282996986a6d01dcf0b8dd4a4e9b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Fri, 16 Aug 2019 01:29:19 +0800 Subject: [PATCH 030/225] Update Environment.php --- src/async-queue/src/Environment.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/async-queue/src/Environment.php b/src/async-queue/src/Environment.php index a6bb37974..3a59baf43 100644 --- a/src/async-queue/src/Environment.php +++ b/src/async-queue/src/Environment.php @@ -14,6 +14,9 @@ namespace Hyperf\AsyncQueue; class Environment { + /** + * @var bool + */ protected $asyncQueue = false; public function isAsyncQueue(): bool From 5912443b98322499a67f37a7656793469fd64ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 16 Aug 2019 09:24:45 +0800 Subject: [PATCH 031/225] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c87973c4b..2984241b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueue. +## Deleted + +- [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Deleted deprecated method `AsyncQueue::delay`. + # v1.0.11 - 2019-08-15 ## Added From 022183cbe42b5be7c544854beb27fef4234fba01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 16 Aug 2019 09:27:31 +0800 Subject: [PATCH 032/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2984241b4..e447787c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Added -- [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueue. +- [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. ## Deleted From 8749a1c0726debdd60a725349113d9a4f8101c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 16 Aug 2019 09:32:43 +0800 Subject: [PATCH 033/225] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f32f04e9..1f9f1f150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ - [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Optimized server and Fixed middleware that user defined does not works. - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. +## Deprecated + +- [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Class `Hyperf\JsonRpc\HttpServerFactory`, `Hyperf\HttpServer\ServerFactory` will be discarded. Bacause the Server is optimized, factory is useless. + ## Deleted - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Deleted deprecated method `AsyncQueue::delay`. From 7be6e35d44a6b72231b9273ab65aeae8abd0fc81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 16 Aug 2019 09:56:51 +0800 Subject: [PATCH 034/225] Update --- CHANGELOG.md | 2 ++ bin/release.sh | 2 +- bin/split-linux.sh | 2 +- bin/split.sh | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fe1a7b36..6c0859e03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Deleted deprecated method `AsyncQueue::delay`. +# v1.0.12 - TBD + ## Added - [#405](https://github.com/hyperf-cloud/hyperf/pull/405) Added Context::override() method. diff --git a/bin/release.sh b/bin/release.sh index 5e9c11696..1c7cf2d09 100755 --- a/bin/release.sh +++ b/bin/release.sh @@ -9,7 +9,7 @@ then fi NOW=$(date +%s) -CURRENT_BRANCH="1.0" +CURRENT_BRANCH="master" VERSION=$1 BASEPATH=$(cd `dirname $0`; cd ../src/; pwd) diff --git a/bin/split-linux.sh b/bin/split-linux.sh index fb21fa15b..381ecee0a 100755 --- a/bin/split-linux.sh +++ b/bin/split-linux.sh @@ -3,7 +3,7 @@ set -e set -x -CURRENT_BRANCH="1.0" +CURRENT_BRANCH="master" BASEPATH=$(cd `dirname $0`; cd ../src/; pwd) REPOS=$@ diff --git a/bin/split.sh b/bin/split.sh index 9ea7cf47c..68cbc71b1 100755 --- a/bin/split.sh +++ b/bin/split.sh @@ -3,7 +3,7 @@ set -e set -x -CURRENT_BRANCH="1.0" +CURRENT_BRANCH="master" BASEPATH=$(cd `dirname $0`; cd ../src/; pwd) REPOS=$@ From 1d0d08abad3ab291e48a6b321baddaada02563c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Fri, 16 Aug 2019 12:57:22 +0800 Subject: [PATCH 035/225] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 546ea55b3..aa54e1240 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ In addition to providing `MySQL coroutine client` and `Redis coroutine client`, # Original intention -Although many new PHP frameworks have appeared, we still haven't seen a comprehensive framework, which introduces an elegant design and ultra-high performance, suitable for PHP microservices and as an evangelist of PHP microservices. For the original intention of Hyperf and its team members, we will continue to invest to it, and you are welcome to join us to participate in open source construction. +Although many new PHP frameworks have appeared, we still haven't seen a comprehensive framework, which introduces an elegant design and ultra-high performance, suitable for PHP microservices and as an evangelist of PHP microservices. For the original intention of Hyperf and its team members, we will continue to invest in it, and you are welcome to join us to participate in open source development. # Design concept From 0d4162416184c3eee88b92375f4742137193ecc3 Mon Sep 17 00:00:00 2001 From: Bi Zhiming Date: Fri, 16 Aug 2019 19:56:30 +0800 Subject: [PATCH 036/225] =?UTF-8?q?=E9=94=99=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 错别字 --- doc/zh/exception-handler.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/exception-handler.md b/doc/zh/exception-handler.md index 86db76929..eb2bfa73f 100644 --- a/doc/zh/exception-handler.md +++ b/doc/zh/exception-handler.md @@ -1,7 +1,7 @@ # 异常处理器 在 `Hyperf` 里,业务代码都运行在 `Worker进程` 上,也就意味着一旦任意一个请求的业务存在没有捕获处理的异常的话,都会导致对应的 `Worker进程` 被中断退出,虽然被中断的 `Worker进程` 仍会被重新拉起,但对服务而已也是不能接受的,且捕获异常并输出合理的报错内容给客户端也是更加友好的。 -我们可以通过对各个 `server` 定义不同的 `异常处理器(ExceptionHandler)`,一旦业务流程存在没有捕获的异常,到会被传递到已注册的 `异常处理器(ExceptionHandler)` 去处理。 +我们可以通过对各个 `server` 定义不同的 `异常处理器(ExceptionHandler)`,一旦业务流程存在没有捕获的异常,都会被传递到已注册的 `异常处理器(ExceptionHandler)` 去处理。 ## 自定义一个异常处理 From 7557336fcbe11d9adad3b4c6d40849e34938b601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sat, 17 Aug 2019 09:02:40 +0800 Subject: [PATCH 037/225] Optimized code. --- .../Listener/InitWebSocketServerListener.php | 54 ------------------- src/websocket-server/src/Server.php | 12 ++--- 2 files changed, 4 insertions(+), 62 deletions(-) delete mode 100644 src/websocket-server/src/Listener/InitWebSocketServerListener.php diff --git a/src/websocket-server/src/Listener/InitWebSocketServerListener.php b/src/websocket-server/src/Listener/InitWebSocketServerListener.php deleted file mode 100644 index 5b63b13fb..000000000 --- a/src/websocket-server/src/Listener/InitWebSocketServerListener.php +++ /dev/null @@ -1,54 +0,0 @@ -container = $container; - } - - public function listen(): array - { - return [ - BeforeMainServerStart::class, - ]; - } - - /** - * @param BeforeMainServerStart $event - */ - public function process(object $event) - { - if (! $this->container->has(Server::class)) { - return; - } - $server = $this->container->get(Server::class); - $event->server instanceof \Swoole\WebSocket\Server && $server->setServer($event->server); - } -} diff --git a/src/websocket-server/src/Server.php b/src/websocket-server/src/Server.php index 5e6086d87..d76bd3eff 100644 --- a/src/websocket-server/src/Server.php +++ b/src/websocket-server/src/Server.php @@ -24,6 +24,7 @@ use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpServer\MiddlewareManager; +use Hyperf\Server\ServerFactory; use Hyperf\Utils\Context; use Hyperf\WebSocketServer\Collector\FdCollector; use Hyperf\WebSocketServer\Exception\Handler\WebSocketExceptionHandler; @@ -64,11 +65,6 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On */ protected $logger; - /** - * @var WebSocketServer - */ - protected $server; - /** * @var array */ @@ -98,9 +94,9 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On ]); } - public function setServer(WebSocketServer $server): void + public function getServer(): WebSocketServer { - $this->server = $server; + return $this->container->get(ServerFactory::class)->getServer()->getServer(); } public function onHandShake(SwooleRequest $request, SwooleResponse $response): void @@ -130,7 +126,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On defer(function () use ($request, $class) { $instance = $this->container->get($class); if ($instance instanceof OnOpenInterface) { - $instance->onOpen($this->server, $request); + $instance->onOpen($this->getServer(), $request); } }); } From 5f677361fb75234e96c29e2b7aec251bf00dbee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sat, 17 Aug 2019 10:07:13 +0800 Subject: [PATCH 038/225] Added Sender to fix fd does not found when server::push. --- .../src/Exception/MethodInvalidException.php | 19 +++ .../src/Listener/InitSenderListener.php | 53 +++++++++ .../src/Listener/OnPipeMessageListener.php | 88 ++++++++++++++ src/websocket-server/src/Sender.php | 110 ++++++++++++++++++ .../src/SenderPipeMessage.php | 32 +++++ 5 files changed, 302 insertions(+) create mode 100644 src/websocket-server/src/Exception/MethodInvalidException.php create mode 100644 src/websocket-server/src/Listener/InitSenderListener.php create mode 100644 src/websocket-server/src/Listener/OnPipeMessageListener.php create mode 100644 src/websocket-server/src/Sender.php create mode 100644 src/websocket-server/src/SenderPipeMessage.php diff --git a/src/websocket-server/src/Exception/MethodInvalidException.php b/src/websocket-server/src/Exception/MethodInvalidException.php new file mode 100644 index 000000000..99a654830 --- /dev/null +++ b/src/websocket-server/src/Exception/MethodInvalidException.php @@ -0,0 +1,19 @@ +container = $container; + } + + /** + * @return string[] returns the events that you want to listen + */ + public function listen(): array + { + return [ + AfterWorkerStart::class, + ]; + } + + public function process(object $event) + { + if ($event instanceof AfterWorkerStart) { + $sender = $this->container->get(Sender::class); + $sender->setWorkerId($event->workerId); + } + } +} diff --git a/src/websocket-server/src/Listener/OnPipeMessageListener.php b/src/websocket-server/src/Listener/OnPipeMessageListener.php new file mode 100644 index 000000000..b476fe5f6 --- /dev/null +++ b/src/websocket-server/src/Listener/OnPipeMessageListener.php @@ -0,0 +1,88 @@ +container = $container; + $this->config = $config; + $this->logger = $logger; + } + + /** + * @return string[] returns the events that you want to listen + */ + public function listen(): array + { + return [ + OnPipeMessage::class, + ]; + } + + /** + * Handle the Event when the event is triggered, all listeners will + * complete before the event is returned to the EventDispatcher. + */ + public function process(object $event) + { + if ($event instanceof OnPipeMessage && $event->data instanceof SenderPipeMessage) { + /** @var SenderPipeMessage $message */ + $message = $event->data; + + try { + $sender = $this->container->get(Sender::class); + + $sender->proxy($message->name, $message->arguments); + } catch (\Throwable $exception) { + $formatter = $this->container->get(FormatterInterface::class); + $this->logger->warning($formatter->format($exception)); + } + } + } + + protected function getServer() + { + return $this->container->get(ServerFactory::class)->getServer()->getServer(); + } +} diff --git a/src/websocket-server/src/Sender.php b/src/websocket-server/src/Sender.php new file mode 100644 index 000000000..ddfa6e7a3 --- /dev/null +++ b/src/websocket-server/src/Sender.php @@ -0,0 +1,110 @@ +container = $container; + $this->logger = $container->get(StdoutLoggerInterface::class); + } + + public function __call($name, $arguments) + { + if (! $this->proxy($name, $arguments)) { + $this->sendPipeMessage($name, $arguments); + } + } + + public function proxy($name, $arguments): bool + { + $fd = $this->getFdFromProxyMethod($name, $arguments); + if ($fd === false) { + throw new MethodInvalidException($arguments); + } + + $ret = $this->check($fd); + if ($ret) { + $this->getServer()->push(...$arguments); + $this->logger->debug("[WebSocket] Worker.{$this->workerId} send to #{$fd}"); + } + + return $ret; + } + + /** + * @param int $workerId + */ + public function setWorkerId(int $workerId): void + { + $this->workerId = $workerId; + } + + public function check($fd): bool + { + $server = $this->getServer(); + $info = $server->connection_info($fd); + + if ($info && $info['websocket_status'] == WEBSOCKET_STATUS_ACTIVE) { + return true; + } + + return false; + } + + /** + * @param $method + * @param mixed $arguments + * @return null|bool|int + */ + protected function getFdFromProxyMethod($method, $arguments) + { + if (in_array($method, ['push', 'send', 'sendto'])) { + return $arguments[0]; + } + + return false; + } + + protected function getServer() + { + return $this->container->get(ServerFactory::class)->getServer()->getServer(); + } + + protected function sendPipeMessage($name, $arguments) + { + $server = $this->getServer(); + $workerCount = $server->setting['worker_num'] - 1; + for ($workerId = 0; $workerId <= $workerCount; ++$workerId) { + if ($workerId !== $this->workerId) { + $server->sendMessage(new SenderPipeMessage($name, $arguments), $workerId); + $this->logger->debug("[WebSocket] Let Worker.{$workerId} try to {$name}."); + } + } + } +} diff --git a/src/websocket-server/src/SenderPipeMessage.php b/src/websocket-server/src/SenderPipeMessage.php new file mode 100644 index 000000000..ef4c46cbe --- /dev/null +++ b/src/websocket-server/src/SenderPipeMessage.php @@ -0,0 +1,32 @@ +name = $name; + $this->arguments = $arguments; + } +} From b22b9357ad57583cfbf48d217b6dac10ffaf7622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sat, 17 Aug 2019 10:13:25 +0800 Subject: [PATCH 039/225] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c0859e03..47f5d9bff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Added - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. +- [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Added `Sender` to fix fd not found when use method `server::send`. ## Deleted From bcc4152cd438779ec8e2a59562c757815597b458 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sat, 17 Aug 2019 22:51:45 +0800 Subject: [PATCH 040/225] Optimized the exception message --- src/grpc-server/src/CoreMiddleware.php | 2 +- src/http-server/src/CoreMiddleware.php | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/grpc-server/src/CoreMiddleware.php b/src/grpc-server/src/CoreMiddleware.php index 0a6c513d8..c7ca57c1e 100644 --- a/src/grpc-server/src/CoreMiddleware.php +++ b/src/grpc-server/src/CoreMiddleware.php @@ -51,7 +51,7 @@ class CoreMiddleware extends HttpCoreMiddleware $dispatched = $request->getAttribute(Dispatched::class); if (! $dispatched instanceof Dispatched) { - throw new ServerException('The object is not instanceof `HyperfHttpServerRouterDispatched`.'); + throw new ServerException(sprintf('The dispatched object is not a %s object.', Dispatched::class)); } switch ($dispatched->status) { diff --git a/src/http-server/src/CoreMiddleware.php b/src/http-server/src/CoreMiddleware.php index 1ff0a410a..b14f5ac0f 100644 --- a/src/http-server/src/CoreMiddleware.php +++ b/src/http-server/src/CoreMiddleware.php @@ -68,9 +68,7 @@ class CoreMiddleware implements CoreMiddlewareInterface public function dispatch(ServerRequestInterface $request): array { - $uri = $request->getUri(); - - $routes = $this->dispatcher->dispatch($request->getMethod(), $uri->getPath()); + $routes = $this->dispatcher->dispatch($request->getMethod(), $request->getUri()->getPath()); $dispatched = new Dispatched($routes); $request = $request->withAttribute(Dispatched::class, $dispatched); @@ -88,7 +86,7 @@ class CoreMiddleware implements CoreMiddlewareInterface $dispatched = $request->getAttribute(Dispatched::class); if (! $dispatched instanceof Dispatched) { - throw new ServerException('The object is not instanceof `HyperfHttpServerRouterDispatched`.'); + throw new ServerException(sprintf('The dispatched object is not a %s object.', Dispatched::class)); } switch ($dispatched->status) { From 08fe7892ff699b8e751ccc37fc0591c8aece3b7d Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sat, 17 Aug 2019 23:19:27 +0800 Subject: [PATCH 041/225] Rename MethodInvalidException to InvalidMethodException --- ...ception.php => InvalidMethodException.php} | 2 +- src/websocket-server/src/Sender.php | 37 ++++++++++--------- 2 files changed, 21 insertions(+), 18 deletions(-) rename src/websocket-server/src/Exception/{MethodInvalidException.php => InvalidMethodException.php} (86%) diff --git a/src/websocket-server/src/Exception/MethodInvalidException.php b/src/websocket-server/src/Exception/InvalidMethodException.php similarity index 86% rename from src/websocket-server/src/Exception/MethodInvalidException.php rename to src/websocket-server/src/Exception/InvalidMethodException.php index 99a654830..f6187bcdb 100644 --- a/src/websocket-server/src/Exception/MethodInvalidException.php +++ b/src/websocket-server/src/Exception/InvalidMethodException.php @@ -14,6 +14,6 @@ namespace Hyperf\WebSocketServer\Exception; use Hyperf\Server\Exception\ServerException; -class MethodInvalidException extends ServerException +class InvalidMethodException extends ServerException { } diff --git a/src/websocket-server/src/Sender.php b/src/websocket-server/src/Sender.php index ddfa6e7a3..b5954575e 100644 --- a/src/websocket-server/src/Sender.php +++ b/src/websocket-server/src/Sender.php @@ -14,7 +14,7 @@ namespace Hyperf\WebSocketServer; use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\Server\ServerFactory; -use Hyperf\WebSocketServer\Exception\MethodInvalidException; +use Hyperf\WebSocketServer\Exception\InvalidMethodException; use Psr\Container\ContainerInterface; /** @@ -22,10 +22,19 @@ use Psr\Container\ContainerInterface; */ class Sender { + /** + * @var \Psr\Container\ContainerInterface + */ protected $container; + /** + * @var \Hyperf\Contract\StdoutLoggerInterface + */ protected $logger; + /** + * @var int + */ protected $workerId; public function __construct(ContainerInterface $container) @@ -41,25 +50,22 @@ class Sender } } - public function proxy($name, $arguments): bool + public function proxy(string $name, array $arguments): bool { $fd = $this->getFdFromProxyMethod($name, $arguments); if ($fd === false) { - throw new MethodInvalidException($arguments); + throw new InvalidMethodException($arguments); } - $ret = $this->check($fd); - if ($ret) { + $result = $this->check($fd); + if ($result) { $this->getServer()->push(...$arguments); $this->logger->debug("[WebSocket] Worker.{$this->workerId} send to #{$fd}"); } - return $ret; + return $result; } - /** - * @param int $workerId - */ public function setWorkerId(int $workerId): void { $this->workerId = $workerId; @@ -67,10 +73,9 @@ class Sender public function check($fd): bool { - $server = $this->getServer(); - $info = $server->connection_info($fd); + $info = $this->getServer()->connection_info($fd); - if ($info && $info['websocket_status'] == WEBSOCKET_STATUS_ACTIVE) { + if ($info && $info['websocket_status'] === WEBSOCKET_STATUS_ACTIVE) { return true; } @@ -78,11 +83,9 @@ class Sender } /** - * @param $method - * @param mixed $arguments * @return null|bool|int */ - protected function getFdFromProxyMethod($method, $arguments) + protected function getFdFromProxyMethod(string $method, array $arguments) { if (in_array($method, ['push', 'send', 'sendto'])) { return $arguments[0]; @@ -91,12 +94,12 @@ class Sender return false; } - protected function getServer() + protected function getServer(): \Swoole\Server { return $this->container->get(ServerFactory::class)->getServer()->getServer(); } - protected function sendPipeMessage($name, $arguments) + protected function sendPipeMessage(string $name, array $arguments): void { $server = $this->getServer(); $workerCount = $server->setting['worker_num'] - 1; From 6b095613b79fab6dff075d0b39cfb3956221c868 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sat, 17 Aug 2019 23:20:08 +0800 Subject: [PATCH 042/225] Use ConfigProvider instead of Listener annotation --- src/websocket-server/src/ConfigProvider.php | 6 +++++- src/websocket-server/src/Listener/InitSenderListener.php | 6 +----- .../src/Listener/OnPipeMessageListener.php | 7 ++----- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/websocket-server/src/ConfigProvider.php b/src/websocket-server/src/ConfigProvider.php index ae41ec441..47f1cc411 100644 --- a/src/websocket-server/src/ConfigProvider.php +++ b/src/websocket-server/src/ConfigProvider.php @@ -12,6 +12,8 @@ declare(strict_types=1); namespace Hyperf\WebSocketServer; +use Hyperf\WebSocketServer\Listener; + class ConfigProvider { public function __invoke(): array @@ -19,7 +21,9 @@ class ConfigProvider return [ 'dependencies' => [ ], - 'commands' => [ + 'listeners' => [ + Listener\InitSenderListener::class, + Listener\OnPipeMessageListener::class, ], 'scan' => [ 'paths' => [ diff --git a/src/websocket-server/src/Listener/InitSenderListener.php b/src/websocket-server/src/Listener/InitSenderListener.php index b4e795ea7..41082ddc5 100644 --- a/src/websocket-server/src/Listener/InitSenderListener.php +++ b/src/websocket-server/src/Listener/InitSenderListener.php @@ -12,15 +12,11 @@ declare(strict_types=1); namespace Hyperf\WebSocketServer\Listener; -use Hyperf\Event\Annotation\Listener; use Hyperf\Event\Contract\ListenerInterface; use Hyperf\Framework\Event\AfterWorkerStart; use Hyperf\WebSocketServer\Sender; use Psr\Container\ContainerInterface; -/** - * @Listener - */ class InitSenderListener implements ListenerInterface { /** @@ -45,7 +41,7 @@ class InitSenderListener implements ListenerInterface public function process(object $event) { - if ($event instanceof AfterWorkerStart) { + if ($this->container->has(Sender::class)) { $sender = $this->container->get(Sender::class); $sender->setWorkerId($event->workerId); } diff --git a/src/websocket-server/src/Listener/OnPipeMessageListener.php b/src/websocket-server/src/Listener/OnPipeMessageListener.php index b476fe5f6..d382e06c5 100644 --- a/src/websocket-server/src/Listener/OnPipeMessageListener.php +++ b/src/websocket-server/src/Listener/OnPipeMessageListener.php @@ -14,7 +14,6 @@ namespace Hyperf\WebSocketServer\Listener; use Hyperf\Contract\ConfigInterface; use Hyperf\Contract\StdoutLoggerInterface; -use Hyperf\Event\Annotation\Listener; use Hyperf\Event\Contract\ListenerInterface; use Hyperf\ExceptionHandler\Formatter\FormatterInterface; use Hyperf\Framework\Event\OnPipeMessage; @@ -22,10 +21,8 @@ use Hyperf\Server\ServerFactory; use Hyperf\WebSocketServer\Sender; use Hyperf\WebSocketServer\SenderPipeMessage; use Psr\Container\ContainerInterface; +use Swoole\Server; -/** - * @Listener - */ class OnPipeMessageListener implements ListenerInterface { /** @@ -81,7 +78,7 @@ class OnPipeMessageListener implements ListenerInterface } } - protected function getServer() + protected function getServer(): Server { return $this->container->get(ServerFactory::class)->getServer()->getServer(); } From 585ca314062a25845f1da1db985b947e20076609 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sat, 17 Aug 2019 23:20:21 +0800 Subject: [PATCH 043/225] Add typehint --- src/websocket-server/src/SenderPipeMessage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/websocket-server/src/SenderPipeMessage.php b/src/websocket-server/src/SenderPipeMessage.php index ef4c46cbe..21c7496c4 100644 --- a/src/websocket-server/src/SenderPipeMessage.php +++ b/src/websocket-server/src/SenderPipeMessage.php @@ -24,7 +24,7 @@ class SenderPipeMessage */ public $arguments; - public function __construct($name, $arguments) + public function __construct(string $name, array $arguments) { $this->name = $name; $this->arguments = $arguments; From c64adc21c9eac6637e08b7a3e2dbcbcb3e450de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 18 Aug 2019 00:09:31 +0800 Subject: [PATCH 044/225] Optimized code. --- .../src/Contract/CoreMiddlewareInterface.php | 12 +----------- src/http-server/src/CoreMiddleware.php | 5 ++--- src/http-server/src/Server.php | 9 +++------ src/http-server/tests/CoreMiddlewareTest.php | 9 ++++++--- src/rpc-server/src/Server.php | 2 +- src/websocket-server/src/Server.php | 19 ++++++++----------- 6 files changed, 21 insertions(+), 35 deletions(-) diff --git a/src/http-server/src/Contract/CoreMiddlewareInterface.php b/src/http-server/src/Contract/CoreMiddlewareInterface.php index fd7372554..587519b35 100644 --- a/src/http-server/src/Contract/CoreMiddlewareInterface.php +++ b/src/http-server/src/Contract/CoreMiddlewareInterface.php @@ -12,20 +12,10 @@ declare(strict_types=1); namespace Hyperf\HttpServer\Contract; -use Hyperf\HttpServer\Router\Dispatched; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; interface CoreMiddlewareInterface extends MiddlewareInterface { - /** - * @param ServerRequestInterface $request - * @return array - * - * [ - * @var ServerRequestInterface $requst, - * @var Dispatched $dispatched, - * ] - */ - public function dispatch(ServerRequestInterface $request): array; + public function dispatch(ServerRequestInterface $request): ServerRequestInterface; } diff --git a/src/http-server/src/CoreMiddleware.php b/src/http-server/src/CoreMiddleware.php index b14f5ac0f..f35611a97 100644 --- a/src/http-server/src/CoreMiddleware.php +++ b/src/http-server/src/CoreMiddleware.php @@ -66,14 +66,13 @@ class CoreMiddleware implements CoreMiddlewareInterface $this->methodDefinitionCollector = $this->container->get(MethodDefinitionCollectorInterface::class); } - public function dispatch(ServerRequestInterface $request): array + public function dispatch(ServerRequestInterface $request): ServerRequestInterface { $routes = $this->dispatcher->dispatch($request->getMethod(), $request->getUri()->getPath()); $dispatched = new Dispatched($routes); - $request = $request->withAttribute(Dispatched::class, $dispatched); - return [$request, $dispatched]; + return Context::set(ServerRequestInterface::class, $request->withAttribute(Dispatched::class, $dispatched)); } /** diff --git a/src/http-server/src/Server.php b/src/http-server/src/Server.php index b90c91dfe..18ddc865c 100644 --- a/src/http-server/src/Server.php +++ b/src/http-server/src/Server.php @@ -92,12 +92,9 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface try { [$psr7Request, $psr7Response] = $this->initRequestAndResponse($request, $response); - /** - * @var array - * @var ServerRequestInterface $psr7Request - * @var Dispatched $dispatched - */ - [$psr7Request, $dispatched] = $this->coreMiddleware->dispatch($psr7Request); + $psr7Request = $this->coreMiddleware->dispatch($psr7Request); + /** @var Dispatched $dispatched */ + $dispatched = $psr7Request->getAttribute(Dispatched::class); $middlewares = $this->middlewares; if ($dispatched->isFound()) { $registedMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod()); diff --git a/src/http-server/tests/CoreMiddlewareTest.php b/src/http-server/tests/CoreMiddlewareTest.php index ad583fd64..c4c4719b6 100644 --- a/src/http-server/tests/CoreMiddlewareTest.php +++ b/src/http-server/tests/CoreMiddlewareTest.php @@ -114,7 +114,8 @@ class CoreMiddlewareTest extends TestCase $middleware = new CoreMiddleware($container, 'http'); $request = new Request('GET', new Uri('/user')); - [$request, $dispatched] = $middleware->dispatch($request); + $request = $middleware->dispatch($request); + $dispatched = $request->getAttribute(Dispatched::class); $this->assertInstanceOf(Request::class, $request); $this->assertInstanceOf(Dispatched::class, $dispatched); $this->assertInstanceOf(Handler::class, $dispatched->handler); @@ -124,7 +125,8 @@ class CoreMiddlewareTest extends TestCase $this->assertTrue($dispatched->isFound()); $request = new Request('GET', new Uri('/user/123')); - [$request, $dispatched] = $middleware->dispatch($request); + $request = $middleware->dispatch($request); + $dispatched = $request->getAttribute(Dispatched::class); $this->assertInstanceOf(Request::class, $request); $this->assertInstanceOf(Dispatched::class, $dispatched); $this->assertInstanceOf(Handler::class, $dispatched->handler); @@ -134,7 +136,8 @@ class CoreMiddlewareTest extends TestCase $this->assertTrue($dispatched->isFound()); $request = new Request('GET', new Uri('/users')); - [$request, $dispatched] = $middleware->dispatch($request); + $request = $middleware->dispatch($request); + $dispatched = $request->getAttribute(Dispatched::class); $this->assertInstanceOf(Request::class, $request); $this->assertInstanceOf(Dispatched::class, $dispatched); $this->assertSame($dispatched, $request->getAttribute(Dispatched::class)); diff --git a/src/rpc-server/src/Server.php b/src/rpc-server/src/Server.php index bab6dd6e0..ebb8d0641 100644 --- a/src/rpc-server/src/Server.php +++ b/src/rpc-server/src/Server.php @@ -108,7 +108,7 @@ abstract class Server implements OnReceiveInterface, MiddlewareInitializerInterf // $middlewares = array_merge($this->middlewares, MiddlewareManager::get()); $middlewares = $this->middlewares; - [$request] = $this->coreMiddleware->dispatch($request); + $request = $this->coreMiddleware->dispatch($request); $response = $this->dispatcher->dispatch($request, $middlewares, $this->coreMiddleware); } catch (Throwable $throwable) { diff --git a/src/websocket-server/src/Server.php b/src/websocket-server/src/Server.php index 41555d677..0a493fc8e 100644 --- a/src/websocket-server/src/Server.php +++ b/src/websocket-server/src/Server.php @@ -120,12 +120,9 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On throw new WebSocketHandeShakeException('sec-websocket-key is invalid!'); } - /** - * @var array - * @var ServerRequestInterface $psr7Request - * @var Dispatched $dispatched - */ - [$psr7Request, $dispatched] = $this->coreMiddleware->dispatch($psr7Request); + $psr7Request = $this->coreMiddleware->dispatch($psr7Request); + /** @var Dispatched $dispatched */ + $dispatched = $psr7Request->getAttribute(Dispatched::class); $middlewares = $this->middlewares; if ($dispatched->isFind()) { $registedMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod()); @@ -136,7 +133,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On $class = $psr7Response->getAttribute('class'); - if (! empty($class)) { + if (!empty($class)) { FdCollector::set($request->fd, $class); defer(function () use ($request, $class) { @@ -152,7 +149,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On $psr7Response = $exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers); } finally { // Send the Response to client. - if (! $psr7Response || ! $psr7Response instanceof Psr7Response) { + if (!$psr7Response || !$psr7Response instanceof Psr7Response) { return; } $psr7Response->send(); @@ -162,14 +159,14 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On public function onMessage(\Swoole\Server $server, Frame $frame): void { $fdObj = FdCollector::get($frame->fd); - if (! $fdObj) { + if (!$fdObj) { $this->logger->warning(sprintf('WebSocket: fd[%d] does not exist.', $frame->fd)); return; } $instance = $this->container->get($fdObj->class); - if (! $instance instanceof OnMessageInterface) { + if (!$instance instanceof OnMessageInterface) { $this->logger->warning("{$instance} is not instanceof " . OnMessageInterface::class); return; } @@ -182,7 +179,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On $this->logger->debug(sprintf('WebSocket: fd[%d] closed.', $fd)); $fdObj = FdCollector::get($fd); - if (! $fdObj) { + if (!$fdObj) { return; } $instance = $this->container->get($fdObj->class); From a516b041f20af57c3d72be75c818029289117280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 18 Aug 2019 00:17:28 +0800 Subject: [PATCH 045/225] Fixed bug. --- src/json-rpc/tests/AnyParamCoreMiddlewareTest.php | 4 ++-- src/json-rpc/tests/CoreMiddlewareTest.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php b/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php index bb28b4ee2..ba8837815 100644 --- a/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php +++ b/src/json-rpc/tests/AnyParamCoreMiddlewareTest.php @@ -68,7 +68,7 @@ class AnyParamCoreMiddlewareTest extends TestCase ['value' => 2], ]); - [$request] = $middleware->dispatch($request); + $request = $middleware->dispatch($request); Context::set(ResponseInterface::class, new Response()); $response = $middleware->process($request, $handler); @@ -92,7 +92,7 @@ class AnyParamCoreMiddlewareTest extends TestCase ->withParsedBody([3, 0]); Context::set(ResponseInterface::class, new Response()); - [$request] = $middleware->dispatch($request); + $request = $middleware->dispatch($request); try { $response = $middleware->process($request, $handler); } catch (\Throwable $exception) { diff --git a/src/json-rpc/tests/CoreMiddlewareTest.php b/src/json-rpc/tests/CoreMiddlewareTest.php index 00786da2a..520864a20 100644 --- a/src/json-rpc/tests/CoreMiddlewareTest.php +++ b/src/json-rpc/tests/CoreMiddlewareTest.php @@ -64,7 +64,7 @@ class CoreMiddlewareTest extends TestCase ->withParsedBody([1, 2]); Context::set(ResponseInterface::class, new Response()); - [$request] = $middleware->dispatch($request); + $request = $middleware->dispatch($request); $response = $middleware->process($request, $handler); $this->assertEquals(200, $response->getStatusCode()); $ret = json_decode((string) $response->getBody(), true); @@ -87,7 +87,7 @@ class CoreMiddlewareTest extends TestCase ->withParsedBody([3, 0]); Context::set(ResponseInterface::class, new Response()); - [$request] = $middleware->dispatch($request); + $request = $middleware->dispatch($request); try { $response = $middleware->process($request, $handler); @@ -118,7 +118,7 @@ class CoreMiddlewareTest extends TestCase ->withParsedBody([3, 0]); Context::set(ResponseInterface::class, new Response()); - [$request] = $middleware->dispatch($request); + $request = $middleware->dispatch($request); try { $response = $middleware->process($request, $handler); From d134fd5cdb1c30e8626baa2dd65f86346f3ad91d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 18 Aug 2019 00:22:45 +0800 Subject: [PATCH 046/225] Deleted ServerFactory. --- CHANGELOG.md | 5 +---- src/http-server/src/ServerFactory.php | 26 ------------------------- src/json-rpc/src/HttpServerFactory.php | 27 -------------------------- 3 files changed, 1 insertion(+), 57 deletions(-) delete mode 100644 src/http-server/src/ServerFactory.php delete mode 100644 src/json-rpc/src/HttpServerFactory.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f40b7205d..3490006de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,9 @@ - [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Optimized server and Fixed middleware that user defined does not works. - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. -## Deprecated - -- [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Class `Hyperf\JsonRpc\HttpServerFactory`, `Hyperf\HttpServer\ServerFactory` will be discarded. Bacause the Server is optimized, factory is useless. - ## Deleted +- [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Deleted class `Hyperf\JsonRpc\HttpServerFactory`, `Hyperf\HttpServer\ServerFactory`. - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Deleted deprecated method `AsyncQueue::delay`. # v1.0.12 - TBD diff --git a/src/http-server/src/ServerFactory.php b/src/http-server/src/ServerFactory.php deleted file mode 100644 index 0cb2631da..000000000 --- a/src/http-server/src/ServerFactory.php +++ /dev/null @@ -1,26 +0,0 @@ -get(ProtocolManager::class)); - } -} From 40daf67ac5cd6a472d16a9751f6344f2e7a20204 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 18 Aug 2019 00:22:58 +0800 Subject: [PATCH 047/225] Update awesome-components.md --- doc/zh/awesome-components.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/zh/awesome-components.md b/doc/zh/awesome-components.md index 8f550facc..239dd6428 100644 --- a/doc/zh/awesome-components.md +++ b/doc/zh/awesome-components.md @@ -75,3 +75,12 @@ - [hyperf/service-gevernance](https://github.com/hyperf-cloud/service-gevernance) Hyperf 官方提供的服务治理组件 - [hyperf/tracer](https://github.com/hyperf-cloud/tracer) Hyperf 官方提供的 OpenTracing 分布式调用链追踪组件 - [hyperf/circuit-breaker](https://github.com/hyperf-cloud/circuit-breaker) Hyperf 官方提供的服务熔断组件 + +## 热更新/热重载 + +- [ha-ni-cc/hyperf-watch](https://github.com/ha-ni-cc/hyperf-watch) 一个基于 fswatch 实现的通用热更新组件 +- [mix-php/swoolefor](https://github.com/mix-php/swoolefor) 一个由 Mixphp 实现的通用热更新组件 +- [buexplain/go-watch](https://github.com/buexplain/go-watch) 一个基于 Go 语言实现的通用热更新组件 +- [remy/nodemon](https://github.com/remy/nodemon) 一个基于 node.js 实现的通用热更新组件 + +> Warning: 请勿于生产环境使用 `热更新/热重载` 功能 From 47d0ef9a20b76eb79d83ce87a079da61407ad97b Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 18 Aug 2019 00:32:35 +0800 Subject: [PATCH 048/225] Update questions.md --- doc/zh/quick-start/questions.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/zh/quick-start/questions.md b/doc/zh/quick-start/questions.md index 789c0e020..32f992503 100644 --- a/doc/zh/quick-start/questions.md +++ b/doc/zh/quick-start/questions.md @@ -28,17 +28,22 @@ swoole.use_shortname = 'Off' runtime/container/proxy/ ``` -清理命令 -``` +重新生成缓存命令,新缓存会覆盖原目录 +```bash php bin/hyperf.php di:init-proxy ``` -所以单测命令可以使用以下代替 +删除代理类缓存 +```bash +rm -rf ./runtime/container/proxy ``` + +所以单测命令可以使用以下代替: +```bash php bin/hyperf.php di:init-proxy && composer test ``` 同理,启动命令可以使用以下代替 -``` +```bash php bin/hyperf.php di:init-proxy && php bin/hyperf.php start ``` From 2a5c098842879db39e937fa8f01482a3c09117fa Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 18 Aug 2019 00:37:19 +0800 Subject: [PATCH 049/225] Update overview.md --- doc/zh/quick-start/overview.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/zh/quick-start/overview.md b/doc/zh/quick-start/overview.md index e1d5df50f..5d9565d0a 100644 --- a/doc/zh/quick-start/overview.md +++ b/doc/zh/quick-start/overview.md @@ -222,10 +222,11 @@ class IndexController ## 启动 Hyperf 服务 由于 `Hyperf` 内置了协程服务器,也就意味着 `Hyperf` 将以 `CLI` 的形式去运行,所以在定义好路由及实际的逻辑代码之后,我们需要在项目根目录并通过命令行运行 `php bin/hyperf.php start` 来启动服务。 -当 `Console` 界面显示服务启动后便可通过 `cURL` 或 浏览器对服务正常发起访问了,默认情况下上面的例子是访问 `http://127.0.0.1:9501/index/info?id=1`。 +当 `Console` 界面显示服务启动后便可通过 `cURL` 或 浏览器对服务正常发起访问了,默认服务会提供一个首页 `http://127.0.0.1:9501/`,对于本章示例引导的情况下,也就是上面的例子所对应的访问地址为 `http://127.0.0.1:9501/index/info?id=1`。 ## 重新加载代码 由于 `Hyperf` 是持久化的 `CLI` 应用,也就意味着一旦进程启动,已解析的 `PHP` 代码会持久化在进程中,也就意味着启动服务后您再修改的 `PHP` 代码不会改变已启动的服务,如您希望服务重新加载您修改后的代码,您需要通过在启动的 `Console` 中键入 `CTRL + C` 终止服务,再重新执行启动命令完成重启和重新加载。 > Tips: 您也可以将启动 Server 的命令配置在 IDE 上,便可直接通过 IDE 的 `启动/停止` 操作快捷的完成 `启动服务` 或 `重启服务` 的操作。 +> 且非视图开发时可以采用 [TDD(Test-Driven Development)](https://baike.baidu.com/item/TDD/9064369) 测试驱动开发来进行开发,这样不仅可以省略掉服务重启和频繁切换窗口的麻烦,还可保证接口数据的正确性。 From b0275d8be11628f25ebed45cdb2b8d7fed7f598e Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 18 Aug 2019 00:49:00 +0800 Subject: [PATCH 050/225] Update awesome-components.md --- doc/zh/awesome-components.md | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/doc/zh/awesome-components.md b/doc/zh/awesome-components.md index 239dd6428..34ae84326 100644 --- a/doc/zh/awesome-components.md +++ b/doc/zh/awesome-components.md @@ -23,7 +23,7 @@ ## 日志 -- [hyperf/logger](https://github.com/hyperf-cloud/logger) Hyperf 官方提供的基于 PSR-3 的日志管理器 +- [hyperf/logger](https://github.com/hyperf-cloud/logger) Hyperf 官方提供的基于 PSR-3 的日志管理器,一个基于 monolog 的抽象及封装 ## 命令 @@ -51,31 +51,52 @@ - [hyperf/consul](https://github.com/hyperf-cloud/consul) Hyperf 官方提供的 Consul 协程客户端 - [hyperf/elasticsearch](https://github.com/hyperf-cloud/elasticsearch) Hyperf 官方提供的 Elasticsearch 协程客户端 - [hyperf/grpc-client](https://github.com/hyperf-cloud/grpc-client) Hyperf 官方提供的 GRPC 协程客户端 +- [hyperf/etcd](https://github.com/hyperf-cloud/etcd) Hyperf 官方提供的 ETCD 协程客户端 - [hyperf/rpc-client](https://github.com/hyperf-cloud/rpc-client) Hyperf 官方提供的通用 RPC 抽象协程客户端 -- [hyperf/guzzle](https://github.com/hyperf-cloud/guzzle) Hyperf 官方提供的 Guzzle 协程客户端 +- [hyperf/guzzle](https://github.com/hyperf-cloud/guzzle) Hyperf 官方提供的 Guzzle HTTP 协程客户端 - [hyperf/redis](https://github.com/hyperf-cloud/redis) Hyperf 官方提供的 Redis 协程客户端 - [hyperf/websocket-client](https://github.com/hyperf-cloud/websocket-client) Hyperf 官方提供的 WebSocket 协程客户端 -- [hyperf/cache](https://github.com/hyperf-cloud/cache) Hyperf 官方提供的基于 PSR-16 的缓存协程客户端 +- [hyperf/cache](https://github.com/hyperf-cloud/cache) Hyperf 官方提供的基于 PSR-16 的缓存协程客户端,支持注解的使用方式 ## 消息队列 - [hyperf/amqp](https://github.com/hyperf-cloud/amqp) Hyperf 官方提供的 AMQP 协程组件 -- [hyperf/async-queue](https://github.com/hyperf-cloud/async-queue) Hyperf 官方提供的简单的异步队列组件 +- [hyperf/async-queue](https://github.com/hyperf-cloud/async-queue) Hyperf 官方提供的简单的基于 Redis 的异步队列组件 ## 配置中心 - [hyperf/config-apollo](https://github.com/hyperf-cloud/config-apollo) Hyperf 官方提供的 Apollo 配置中心接入组件 - [hyperf/config-aliyun-acm](https://github.com/hyperf-cloud/config-aliyun-acm) Hyperf 官方提供的阿里云 ACM 应用配置服务接入组件 +- [hyperf/config-etcd](https://github.com/hyperf-cloud/config-etcd) Hyperf 官方提供的 ETCD 配置中心接入组件 + +## RPC + +- [hyperf/json-rpc](https://github.com/hyperf-cloud/json-rpc) Hyperf 官方提供的 JSON-RPC 协议组件 ## 服务治理 -- [hyperf/json-rpc](https://github.com/hyperf-cloud/json-rpc) Hyperf 官方提供的 JSON-RPC 协议组件 - [hyperf/rate-limit](https://github.com/hyperf-cloud/rate-limit) Hyperf 官方提供的基于令牌桶算法的限流组件 - [hyperf/load-balancer](https://github.com/hyperf-cloud/load-balancer) Hyperf 官方提供的负载均衡组件 - [hyperf/service-gevernance](https://github.com/hyperf-cloud/service-gevernance) Hyperf 官方提供的服务治理组件 - [hyperf/tracer](https://github.com/hyperf-cloud/tracer) Hyperf 官方提供的 OpenTracing 分布式调用链追踪组件 - [hyperf/circuit-breaker](https://github.com/hyperf-cloud/circuit-breaker) Hyperf 官方提供的服务熔断组件 +## 定时任务 + +- [hyperf/crontab](https://github.com/hyperf-cloud/crontab) Hyperf 官方提供的秒级定时任务组件 + +## ID 生成器 + +- [hyperf/snawflake](https://github.com/hyperf-cloud/snawflake) Hyperf 官方提供的 Snowflake ID 生成器组件 (beta) + +## 文档生成 + +- [hyperf/swagger](https://github.com/hyperf-cloud/swagger) Hyperf 官方提供的 Swagger 文档自动生成组件 (beta) + +## Graphql + +- [hyperf/graphql](https://github.com/hyperf-cloud/graphql) Hyperf 官方提供的 Graphql 服务端组件 (beta) + ## 热更新/热重载 - [ha-ni-cc/hyperf-watch](https://github.com/ha-ni-cc/hyperf-watch) 一个基于 fswatch 实现的通用热更新组件 @@ -83,4 +104,9 @@ - [buexplain/go-watch](https://github.com/buexplain/go-watch) 一个基于 Go 语言实现的通用热更新组件 - [remy/nodemon](https://github.com/remy/nodemon) 一个基于 node.js 实现的通用热更新组件 +## Swoole + +- - [hyperf/swoole-enterprise](https://github.com/hyperf-cloud/swoole-enterprise) Hyperf 官方提供的对接 Swoole Enterprise (Swoole Tracker) 的组件,提供阻塞分析、性能分析、内存泄漏分析、运行状态及调用统计等功能 +- - [hyperf/task](https://github.com/hyperf-cloud/task) Hyperf 官方提供的 Task 组件,对 Swoole 的 Task 机制进行了封装及抽象,提供便捷的注解用法 + > Warning: 请勿于生产环境使用 `热更新/热重载` 功能 From 52d5d1a416ba80b5a34e96d568c341598819e4b0 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 18 Aug 2019 01:41:46 +0800 Subject: [PATCH 051/225] Update README.md --- doc/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/README.md b/doc/README.md index d81b4457e..bb1cf7ca1 100644 --- a/doc/README.md +++ b/doc/README.md @@ -2,7 +2,9 @@ Hyperf 是基于 `Swoole 4.3+` 实现的高性能、高灵活性的 PHP 协程框架,内置协程服务器及大量常用的组件,性能较传统基于 `PHP-FPM` 的框架有质的提升,提供超高性能的同时,也保持着极其灵活的可扩展性,标准组件均基于 [PSR 标准](https://www.php-fig.org/psr) 实现,基于强大的依赖注入设计,保证了绝大部分组件或类都是 `可替换` 与 `可复用` 的。 -框架组件库除了常见的协程版的 `MySQL 客户端`、`Redis 客户端`,还为您准备了协程版的 `Eloquent ORM`、`JSON RPC 服务端及客户端`、`GRPC 服务端及客户端`、`Zipkin (OpenTracing) 客户端`、`Guzzle HTTP 客户端`、`Elasticsearch 客户端`、`Consul 客户端`、`ETCD 客户端`、`AMQP 组件`、`Apollo 配置中心`、`阿里云 ACM 应用配置管理`、`基于令牌桶算法的限流器`、`通用连接池`、`熔断器`、`Swagger 文档生成` 等组件,省去了自己实现对应协程版本的麻烦,Hyperf 还提供了 `依赖注入`、`注解`、`AOP 面向切面编程`、`中间件`、`自定义进程`、`事件管理器`、`Redis/RabbitMQ 消息队列`、`自动模型缓存` 等非常便捷的功能,满足丰富的技术场景和业务场景,开箱即用。 +框架组件库除了常见的协程版的 `MySQL 客户端`、`Redis 客户端`,还为您准备了协程版的 `Eloquent ORM`、`JSON RPC 服务端及客户端`、`GRPC 服务端及客户端`、`WebSocket 服务端和客户端`、`Zipkin (OpenTracing) 客户端`、`Guzzle HTTP 客户端`、`Elasticsearch 客户端`、`Consul 客户端`、`ETCD 客户端`、`AMQP 组件`、`基于 Redis 实现的消息队列`、`Apollo 配置中心`、`ETCD 配置中心`、`阿里云 ACM 配置中心`、`基于令牌桶算法的限流器`、`通用连接池`、`熔断器`、`Swagger 文档自动生成`、`Swoole Tracker (Swoole Enterprise)`、`Blade 和 Smarty 视图引擎` 等组件的提供也省去了自己去实现对应协程版本的麻烦。 + +Hyperf 还提供了 `依赖注入`、`注解`、`AOP 面向切面编程`、`中间件`、`自定义进程`、`事件管理器`、`自动模型缓存`、`Crontab 秒级定时任务` 等非常便捷的功能,满足丰富的技术场景和业务场景,开箱即用。 # 框架初衷 From ce612beec976f38129948e0fadbe3c044be1c595 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 18 Aug 2019 01:41:56 +0800 Subject: [PATCH 052/225] Add configprovider.md --- doc/zh/component-guide/configprovider.md | 78 ++++++++++++++++++++++++ doc/zh/summary.md | 2 +- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 doc/zh/component-guide/configprovider.md diff --git a/doc/zh/component-guide/configprovider.md b/doc/zh/component-guide/configprovider.md new file mode 100644 index 000000000..ca22e8749 --- /dev/null +++ b/doc/zh/component-guide/configprovider.md @@ -0,0 +1,78 @@ +# ConfigProvider 机制 + +ConfigProvider 机制对于 Hyperf 组件化来说是个非常重要的机制,`组件间的解耦` 和 `组件的独立性` 以及 `组件的可重用性` 都是基于这个机制才得以实现。 + +# 什么是 ConfigProvider 机制 ? + +简单来说,就是每个组件都会提供一个 `ConfigProvider`,通常是在组件的根目录提供一个 `ConfigProvider` 的类,`ConfigProvider` 会提供对应组件的所有配置信息,这些信息都会被 Hyperf 框架在启动时加载,最终`ConfigProvider` 内的配置信息会被合并到 `Hyperf\Contract\ConfigInterface` 对应的实现类去,而 `dependencies` 信息则会合并到 `Hyperf\Di\Definition\DefinitionSource` 去,从而实现该组件在 Hyperf 框架下使用时要进行的配置初始化。 + +`ConfigProvider` 本身不具备任何依赖,不继承任何的抽象类和不要求实现任何的接口,只需提供一个 `__invoke` 方法并返回一个对应配置结构的数组即可。 + +# 如何定义一个 ConfigProvider ? + +通常来说,`ConfigProvider` 会定义在组件的根目录下,一个 `ConfigProvider` 类通常如下: + +```php + [], + // 合并到 config/autoload/annotations.php 文件 + 'scan' => [ + 'paths' => [ + __DIR__, + ], + ], + // 默认 Command 的定义,合并到 Hyperf\Contract\ConfigInterface 内,换个方式理解也就是与 config/autoload/commands.php 对应 + 'commands' => [], + // 与 commands 类似 + 'listeners' => [], + ]; + } +} +``` + +只创建一个类并不会被 Hyperf 自动的加载,您仍需在组件的 `composer.json` 添加一些定义,告诉 Hyperf 这是一个 ConfigProvider 类需要被加载,您需要在组件内的 `composer.json` 文件内增加 `extra.hyperf.config` 配置,并指定对应的 `ConfigProvider` 类的命名空间,如下所示: + +```json +{ + "name": "hyperf/foo", + "require": { + "php": ">=7.2" + }, + "autoload": { + "psr-4": { + "Hyperf\\Foo\\": "src/" + } + }, + "extra": { + "hyperf": { + "config": "Hyperf\\Foo\\ConfigProvider" + } + } +} +``` + +定义了之后需执行 `composer install` 或 `composer update` 或 `composer dump-autoload` 等会让 Composer 重新生成 `composer.lock` 文件的命令,才能被正常读取。 + +# ConfigProvider 机制的执行流程 + +关于 `ConfigProvider` 的配置并非一定就是这样去划分,这是一些约定成俗的格式,实际上最终如何来解析这些配置的决定权也在于用户,用户可通过修改 Skeleton 项目的 `config/container.php` 文件内的代码来调整相关的加载,也就意味着,`config/container.php` 文件决定了 `ConfigProvider` 的扫描和加载。 + +# 组件设计规范 + +由于 `composer.json` 内的 `extra` 属性在数据不被利用时无其它作用和影响,顾这些组件内的定义在其它框架使用时,不会造成任何的干扰和影响,顾 `ConfigProvider` 是一种仅作用于 Hyperf 框架的机制,对其它没有利用此机制的框架不会造成任何的影响,这也就为组件的复用打下了基础,但这也要求在进行组件设计时,必须遵循以下规范: + +- 所有类的设计都必须允许通过标准 `OOP` 的使用方式来使用,所有 Hyperf 专有的功能必须作为增强功能并以单独的类来提供,也就意味着在非 Hyperf 框架下仍能通过标准的手段来实现组件的使用; +- 组件的依赖设计如果可满足 [PSR 标准](https://www.php-fig.org/psr) 则优先满足且依赖对应的接口而不是实现类;如 [PSR 标准](https://www.php-fig.org/psr) 没有包含的功能,则可满足由 Hyperf 定义的契约库 [Hyperf/contract](https://github.com/hyperf-cloud/contract) 内的接口时优先满足且依赖对应的接口而不是实现类; +- 对于实现 Hyperf 专有功能所增加的增强功能类,通常来说也会对 Hyperf 的一些组件有依赖,那么这些组件的依赖不应该写在 `composer.json` 的 `require` 项,而是写在 `suggust` 项作为建议项存在; +- 组件设计时不应该通过注解进行任何的依赖注入,注入方式应只使用 `构造函数注入` 的方式,这样同时也能满足在 `OOP` 下的使用; +- 组件设计时不应该通过注解进行任何的功能定义,功能定义应只通过 `ConfigProvider` 来定义; +- 类的设计时应尽可能的不储存状态数据,因为这会导致这个类不能作为长生命周期的对象来提供,也无法很方便的使用依赖注入功能,这样会在一定程度下降低性能,状态数据应都通过 `Hyperf\Utils\Context` 协程上下文来储存; \ No newline at end of file diff --git a/doc/zh/summary.md b/doc/zh/summary.md index 64d13416e..e7ef8cc55 100644 --- a/doc/zh/summary.md +++ b/doc/zh/summary.md @@ -94,4 +94,4 @@ * [指南前言](zh/component-guide/intro.md) * [创建新的组件](zh/component-guide/create.md) - * Hyperf 框架流程介入 + * [ConfigProvider 机制](zh/component-guide/configprovider.md) From 2e18a7e7e8dc242737ff7ec126043d48f2fe96d9 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 18 Aug 2019 01:46:15 +0800 Subject: [PATCH 053/225] Update task.md --- doc/zh/task.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/doc/zh/task.md b/doc/zh/task.md index 34f9b86df..b0fb58744 100644 --- a/doc/zh/task.md +++ b/doc/zh/task.md @@ -105,9 +105,9 @@ $result = $task->handle(Coroutine::id()); Swoole 暂时没有协程化的函数列表 -- mysql:底层使用 libmysqlclient -- curl:底层使用 libcurl(即不能使用CURL驱动的Guzzle) -- mongo:底层使用 mongo-c-client +- mysql,底层使用 libmysqlclient +- curl,底层使用 libcurl,在 Swoole 4.4 后底层进行了协程化(beta) +- mongo,底层使用 mongo-c-client - pdo_pgsql - pdo_ori - pdo_odbc @@ -143,10 +143,8 @@ class MongoTask /** * @Task - * @param string $namespace - * @param array $document */ - public function insert($namespace, $document) + public function insert(string $namespace, array $document) { $writeConcern = new WriteConcern(WriteConcern::MAJORITY, 1000); $bulk = new BulkWrite(); @@ -158,11 +156,8 @@ class MongoTask /** * @Task - * @param string $namespace - * @param array $filter - * @param array $options */ - public function query($namespace, $filter = [], $options = []) + public function query(string $namespace, array $filter = [], array $options = []) { $query = new Query($filter, $options); $cursor = $this->manager()->executeQuery($namespace, $query); From 0f9f3358a97f6c6b9c6df5993447d6a93843339d Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Sun, 18 Aug 2019 17:11:40 +0800 Subject: [PATCH 054/225] Update redis.md --- doc/zh/redis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/redis.md b/doc/zh/redis.md index c4b3e1e2a..a52282bb1 100644 --- a/doc/zh/redis.md +++ b/doc/zh/redis.md @@ -115,7 +115,7 @@ $result = $redis->keys('*'); ### 使用工厂类 -在每个库对应一个静态的场景时,通过代理类是一种很好的区分的方法,但有时候需求可能会更加的动态,这时候我们可以通过 `Hyperf\Redis\RedisFactory` 工厂类来动态的传递 `poolName` 来获得对应的连接池的客户端,而无需为每个库创建代理类,示例如下: +在每个库对应一个固定的使用场景时,通过代理类是一种很好的区分的方法,但有时候需求可能会更加的动态,这时候我们可以通过 `Hyperf\Redis\RedisFactory` 工厂类来动态的传递 `poolName` 来获得对应的连接池的客户端,而无需为每个库创建代理类,示例如下: ```php Date: Mon, 19 Aug 2019 00:58:30 +0800 Subject: [PATCH 055/225] Added observer for model. --- src/database/src/Model/Concerns/HasEvents.php | 84 +++++++++- src/database/src/Model/Events/Event.php | 17 +- src/database/tests/ModelTest.php | 157 +++++++++++++----- .../tests/Stubs/ModelEventListenerStub.php | 38 +++++ src/database/tests/Stubs/ObserverStub.php | 23 +++ 5 files changed, 268 insertions(+), 51 deletions(-) create mode 100644 src/database/tests/Stubs/ModelEventListenerStub.php create mode 100644 src/database/tests/Stubs/ObserverStub.php diff --git a/src/database/src/Model/Concerns/HasEvents.php b/src/database/src/Model/Concerns/HasEvents.php index b7aa4a233..520078c03 100644 --- a/src/database/src/Model/Concerns/HasEvents.php +++ b/src/database/src/Model/Concerns/HasEvents.php @@ -12,22 +12,23 @@ declare(strict_types=1); namespace Hyperf\Database\Model\Concerns; +use Hyperf\Utils\Arr; +use Hyperf\Database\Model\Events\Saved; use Hyperf\Database\Model\Events\Booted; +use Hyperf\Database\Model\Events\Saving; use Hyperf\Database\Model\Events\Booting; use Hyperf\Database\Model\Events\Created; -use Hyperf\Database\Model\Events\Creating; use Hyperf\Database\Model\Events\Deleted; +use Hyperf\Database\Model\Events\Updated; +use Hyperf\Database\Model\Events\Creating; use Hyperf\Database\Model\Events\Deleting; -use Hyperf\Database\Model\Events\ForceDeleted; use Hyperf\Database\Model\Events\Restored; +use Hyperf\Database\Model\Events\Updating; use Hyperf\Database\Model\Events\Restoring; use Hyperf\Database\Model\Events\Retrieved; -use Hyperf\Database\Model\Events\Saved; -use Hyperf\Database\Model\Events\Saving; -use Hyperf\Database\Model\Events\Updated; -use Hyperf\Database\Model\Events\Updating; -use Psr\EventDispatcher\EventDispatcherInterface; +use Hyperf\Database\Model\Events\ForceDeleted; use Psr\EventDispatcher\StoppableEventInterface; +use Psr\EventDispatcher\EventDispatcherInterface; /** * @method retrieved(Retrieved $event) @@ -52,6 +53,57 @@ trait HasEvents */ protected $events = []; + /** + * User exposed observable events. + * + * These are extra user-defined events observers may subscribe to. + * + * @var array + */ + protected static $observables = []; + + /** + * Register observers with the model. + * + * @param object|array|string $classes + * @return void + */ + public static function observe($classes): void + { + $instance = new static; + + foreach (Arr::wrap($classes) as $class) { + $instance->registerObserver($class); + } + } + + /** + * Clear all registered observers with the model. + * + * @return void + */ + public static function clearObservables(): void + { + static::$observables = []; + } + + /** + * Register a single observer with the model. + * + * @param object|string $class + * @return void + */ + protected function registerObserver($class): void + { + $className = is_string($class) ? $class : get_class($class); + + foreach ($this->getDefaultEvents() as $alias => $eventClass) { + if (method_exists($class, $alias)) { + static::$observables[static::class][$alias] = $class; + } + } + } + /** * Set the user-defined event names. */ @@ -105,6 +157,24 @@ trait HasEvents return array_replace($this->getDefaultEvents(), $this->events); } + /** + * Set observable mappings. + */ + public function setObservables(array $observables): self + { + static::$observables[static::class] = $observables; + + return $this; + } + + /** + * Get observable mappings. + */ + public function getObservables(): array + { + return static::$observables[static::class] ?? []; + } + /** * Get the default events of Hyperf Database Model. */ diff --git a/src/database/src/Model/Events/Event.php b/src/database/src/Model/Events/Event.php index d90675bfb..77860a4fc 100644 --- a/src/database/src/Model/Events/Event.php +++ b/src/database/src/Model/Events/Event.php @@ -12,12 +12,12 @@ declare(strict_types=1); namespace Hyperf\Database\Model\Events; -use Hyperf\Database\Model\Model; -use Hyperf\Event\Stoppable; -use Psr\EventDispatcher\StoppableEventInterface; -use function class_basename; use function lcfirst; +use Hyperf\Event\Stoppable; use function method_exists; +use function class_basename; +use Hyperf\Database\Model\Model; +use Psr\EventDispatcher\StoppableEventInterface; abstract class Event implements StoppableEventInterface { @@ -45,6 +45,10 @@ abstract class Event implements StoppableEventInterface return $this->getModel()->{$this->getMethod()}($this); } + if ($observerClass = $this->getObserverClass()) { + return make($observerClass)->{$this->getMethod()}($this); + } + return $this; } @@ -57,4 +61,9 @@ abstract class Event implements StoppableEventInterface { return $this->model; } + + public function getObserverClass(): ?string + { + return $this->getModel()->getObservables()[$this->getMethod()] ?? null; + } } diff --git a/src/database/tests/ModelTest.php b/src/database/tests/ModelTest.php index 4c63d666f..f814bce8d 100644 --- a/src/database/tests/ModelTest.php +++ b/src/database/tests/ModelTest.php @@ -12,60 +12,65 @@ declare(strict_types=1); namespace HyperfTest\Database; -use Carbon\Carbon; +use Mockery; use DateTime; +use stdClass; +use Exception; +use Carbon\Carbon; +use ReflectionClass; use DateTimeImmutable; use DateTimeInterface; -use Exception; -use Hyperf\Database\ConnectionInterface; -use Hyperf\Database\ConnectionInterface as Connection; -use Hyperf\Database\ConnectionResolver; -use Hyperf\Database\ConnectionResolverInterface; -use Hyperf\Database\Connectors\ConnectionFactory; -use Hyperf\Database\Connectors\MySqlConnector; -use Hyperf\Database\Model\Booted; -use Hyperf\Database\Model\Builder; -use Hyperf\Database\Model\Collection; -use Hyperf\Database\Model\Events; -use Hyperf\Database\Model\Model; -use Hyperf\Database\Model\Register; -use Hyperf\Database\Model\Relations\BelongsTo; -use Hyperf\Database\Model\Relations\Relation; -use Hyperf\Database\Query\Grammars\Grammar; -use Hyperf\Database\Query\Processors\Processor; -use Hyperf\Utils\ApplicationContext; -use Hyperf\Utils\Collection as BaseCollection; use Hyperf\Utils\Context; +use PHPUnit\Framework\TestCase; +use Hyperf\Database\Model\Model; +use Hyperf\Database\Model\Booted; +use Hyperf\Database\Model\Events; +use Hyperf\Event\EventDispatcher; +use Hyperf\Database\Model\Builder; +use Hyperf\Event\ListenerProvider; +use HyperfTest\Database\Stubs\User; +use Hyperf\Database\Model\Register; use Hyperf\Utils\InteractsWithTime; +use Hyperf\Utils\ApplicationContext; +use Hyperf\Database\Model\Collection; +use Psr\Container\ContainerInterface; +use Hyperf\Database\ConnectionResolver; +use Hyperf\Database\Model\Events\Event; +use HyperfTest\Database\Stubs\ModelStub; +use Hyperf\Database\ConnectionInterface; +use HyperfTest\Database\Stubs\ObserverStub; +use Hyperf\Database\Query\Grammars\Grammar; use HyperfTest\Database\Stubs\DateModelStub; -use HyperfTest\Database\Stubs\DifferentConnectionModelStub; +use HyperfTest\Database\Stubs\ModelSaveStub; +use HyperfTest\Database\Stubs\ModelWithStub; +use HyperfTest\Database\Stubs\ModelCamelStub; +use Hyperf\Database\Model\Relations\Relation; +use Hyperf\Database\Connectors\MySqlConnector; +use Hyperf\Database\Model\Relations\BelongsTo; +use Hyperf\Utils\Collection as BaseCollection; use HyperfTest\Database\Stubs\KeyTypeModelStub; use HyperfTest\Database\Stubs\ModelAppendsStub; -use HyperfTest\Database\Stubs\ModelBootingTestStub; -use HyperfTest\Database\Stubs\ModelCamelStub; use HyperfTest\Database\Stubs\ModelCastingStub; use HyperfTest\Database\Stubs\ModelDestroyStub; -use HyperfTest\Database\Stubs\ModelDynamicHiddenStub; -use HyperfTest\Database\Stubs\ModelDynamicVisibleStub; -use HyperfTest\Database\Stubs\ModelEventObjectStub; -use HyperfTest\Database\Stubs\ModelFindWithWritePdoStub; -use HyperfTest\Database\Stubs\ModelGetMutatorsStub; -use HyperfTest\Database\Stubs\ModelNonIncrementingStub; -use HyperfTest\Database\Stubs\ModelSaveStub; -use HyperfTest\Database\Stubs\ModelSavingEventStub; -use HyperfTest\Database\Stubs\ModelStub; +use Hyperf\Database\Query\Processors\Processor; +use Hyperf\Database\ConnectionResolverInterface; use HyperfTest\Database\Stubs\ModelStubWithTrait; -use HyperfTest\Database\Stubs\ModelWithoutRelationStub; +use Hyperf\Database\Connectors\ConnectionFactory; +use HyperfTest\Database\Stubs\ModelBootingTestStub; +use HyperfTest\Database\Stubs\ModelEventObjectStub; +use HyperfTest\Database\Stubs\ModelGetMutatorsStub; +use HyperfTest\Database\Stubs\ModelSavingEventStub; use HyperfTest\Database\Stubs\ModelWithoutTableStub; -use HyperfTest\Database\Stubs\ModelWithStub; use HyperfTest\Database\Stubs\NoConnectionModelStub; -use HyperfTest\Database\Stubs\User; -use Mockery; -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface; +use HyperfTest\Database\Stubs\ModelDynamicHiddenStub; +use HyperfTest\Database\Stubs\ModelEventListenerStub; +use HyperfTest\Database\Stubs\ModelDynamicVisibleStub; +use Hyperf\Database\ConnectionInterface as Connection; +use HyperfTest\Database\Stubs\ModelNonIncrementingStub; +use HyperfTest\Database\Stubs\ModelWithoutRelationStub; +use HyperfTest\Database\Stubs\ModelFindWithWritePdoStub; +use HyperfTest\Database\Stubs\DifferentConnectionModelStub; use Psr\EventDispatcher\EventDispatcherInterface as Dispatcher; -use ReflectionClass; -use stdClass; /** * @internal @@ -93,6 +98,8 @@ class ModelTest extends TestCase Carbon::resetToStringFormat(); Booted::$container = []; + + Model::clearObservables(); } public function testAttributeManipulation() @@ -1836,6 +1843,76 @@ class ModelTest extends TestCase $this->assertTrue($called); } + public function testSetObservables() + { + $model = new ModelStub(['id' => 1]); + $model->setObservables($observables = [ + 'created' => 'ObserverClass' + ]); + + $this->assertSame($observables, $model->getObservables()); + } + + public function testObserve() + { + ModelStub::observe(ObserverStub::class); + + $model = new ModelStub(['id' => 1]); + + $this->assertSame(['updating' => ObserverStub::class], $model->getObservables()); + } + + public function testClearObservables() + { + $model = new ModelStub(['id' => 1]); + $model->setObservables($observables = [ + 'created' => 'ObserverClass' + ]); + + ModelStub::clearObservables(); + + $this->assertSame([], $model->getObservables()); + } + + public function testGetObserverClassFromModelEvent() + { + $model = new ModelStub(['id' => 1]); + $model->setObservables($observables = [ + 'updating' => 'ObserverClass' + ]); + + $saving = new Events\Saving($model, 'saving'); + $updating = new Events\Updating($model, 'updating'); + + $this->assertNull($saving->getObserverClass()); + $this->assertSame('ObserverClass', $updating->getObserverClass()); + } + + public function testHandleModelObserver() + { + $listenerProvider = new ListenerProvider; + $listenerProvider->on(Event::class, [new ModelEventListenerStub, 'process']); + + Register::setEventDispatcher(new EventDispatcher($listenerProvider)); + + $model = $this->getMockBuilder(ModelStub::class)->setMethods(['newModelQuery', 'updateTimestamps'])->getMock(); + $query = Mockery::mock(Builder::class); + $query->shouldReceive('where')->once()->with('id', '=', 1); + $query->shouldReceive('update')->once()->with(['foo' => 'bar'])->andReturn(1); + $model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query)); + $model->expects($this->once())->method('updateTimestamps'); + + $model::observe(ObserverStub::class); + + $model->id = 1; + $model->syncOriginal(); + $model->foo = 'foo'; + $model->exists = true; + + $this->assertTrue($model->save()); + + } + public function testModelGenerate() { $this->getContainer(); diff --git a/src/database/tests/Stubs/ModelEventListenerStub.php b/src/database/tests/Stubs/ModelEventListenerStub.php new file mode 100644 index 000000000..fb01bcdaa --- /dev/null +++ b/src/database/tests/Stubs/ModelEventListenerStub.php @@ -0,0 +1,38 @@ +handle(); + } +} diff --git a/src/database/tests/Stubs/ObserverStub.php b/src/database/tests/Stubs/ObserverStub.php new file mode 100644 index 000000000..64691b2af --- /dev/null +++ b/src/database/tests/Stubs/ObserverStub.php @@ -0,0 +1,23 @@ +getModel()->foo = 'bar'; + } +} From 89865cb1567e56cf4a85d2a9621fbfe808725f29 Mon Sep 17 00:00:00 2001 From: Albert Chen Date: Mon, 19 Aug 2019 01:20:27 +0800 Subject: [PATCH 056/225] Pass model as parameter to observer instance. --- src/database/src/Model/Events/Event.php | 2 +- src/database/tests/ModelTest.php | 9 ++++----- .../Stubs/{ObserverStub.php => ModelObserverStub.php} | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) rename src/database/tests/Stubs/{ObserverStub.php => ModelObserverStub.php} (66%) diff --git a/src/database/src/Model/Events/Event.php b/src/database/src/Model/Events/Event.php index 77860a4fc..59c6981c4 100644 --- a/src/database/src/Model/Events/Event.php +++ b/src/database/src/Model/Events/Event.php @@ -46,7 +46,7 @@ abstract class Event implements StoppableEventInterface } if ($observerClass = $this->getObserverClass()) { - return make($observerClass)->{$this->getMethod()}($this); + return make($observerClass)->{$this->getMethod()}($this->getModel()); } return $this; diff --git a/src/database/tests/ModelTest.php b/src/database/tests/ModelTest.php index f814bce8d..9650579c8 100644 --- a/src/database/tests/ModelTest.php +++ b/src/database/tests/ModelTest.php @@ -38,7 +38,6 @@ use Hyperf\Database\ConnectionResolver; use Hyperf\Database\Model\Events\Event; use HyperfTest\Database\Stubs\ModelStub; use Hyperf\Database\ConnectionInterface; -use HyperfTest\Database\Stubs\ObserverStub; use Hyperf\Database\Query\Grammars\Grammar; use HyperfTest\Database\Stubs\DateModelStub; use HyperfTest\Database\Stubs\ModelSaveStub; @@ -53,6 +52,7 @@ use HyperfTest\Database\Stubs\ModelAppendsStub; use HyperfTest\Database\Stubs\ModelCastingStub; use HyperfTest\Database\Stubs\ModelDestroyStub; use Hyperf\Database\Query\Processors\Processor; +use HyperfTest\Database\Stubs\ModelObserverStub; use Hyperf\Database\ConnectionResolverInterface; use HyperfTest\Database\Stubs\ModelStubWithTrait; use Hyperf\Database\Connectors\ConnectionFactory; @@ -1855,11 +1855,11 @@ class ModelTest extends TestCase public function testObserve() { - ModelStub::observe(ObserverStub::class); + ModelStub::observe(ModelObserverStub::class); $model = new ModelStub(['id' => 1]); - $this->assertSame(['updating' => ObserverStub::class], $model->getObservables()); + $this->assertSame(['updating' => ModelObserverStub::class], $model->getObservables()); } public function testClearObservables() @@ -1902,7 +1902,7 @@ class ModelTest extends TestCase $model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query)); $model->expects($this->once())->method('updateTimestamps'); - $model::observe(ObserverStub::class); + $model::observe(ModelObserverStub::class); $model->id = 1; $model->syncOriginal(); @@ -1910,7 +1910,6 @@ class ModelTest extends TestCase $model->exists = true; $this->assertTrue($model->save()); - } public function testModelGenerate() diff --git a/src/database/tests/Stubs/ObserverStub.php b/src/database/tests/Stubs/ModelObserverStub.php similarity index 66% rename from src/database/tests/Stubs/ObserverStub.php rename to src/database/tests/Stubs/ModelObserverStub.php index 64691b2af..7814fe8ea 100644 --- a/src/database/tests/Stubs/ObserverStub.php +++ b/src/database/tests/Stubs/ModelObserverStub.php @@ -12,12 +12,12 @@ declare(strict_types=1); namespace HyperfTest\Database\Stubs; -use Hyperf\Database\Model\Events\Updating; +use Hyperf\Database\Model\Model; -class ObserverStub +class ModelObserverStub { - public function updating(Updating $event) + public function updating(Model $model) { - $event->getModel()->foo = 'bar'; + $model->foo = 'bar'; } } From 537902a2f9c857a3f1647bcab8fd9cd9346a6a94 Mon Sep 17 00:00:00 2001 From: Albert Chen Date: Mon, 19 Aug 2019 01:53:08 +0800 Subject: [PATCH 057/225] Add missing params and return type in `HasEvents.php`. --- src/database/src/Model/Concerns/HasEvents.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/database/src/Model/Concerns/HasEvents.php b/src/database/src/Model/Concerns/HasEvents.php index 520078c03..f07030ff4 100644 --- a/src/database/src/Model/Concerns/HasEvents.php +++ b/src/database/src/Model/Concerns/HasEvents.php @@ -106,6 +106,8 @@ trait HasEvents /** * Set the user-defined event names. + * + * @return self */ public function setEvents(array $events): self { @@ -125,6 +127,7 @@ trait HasEvents * Add some observable event. * * @param array|string $events + * @return void */ public function addEvents($events): void { @@ -133,6 +136,9 @@ trait HasEvents /** * Remove some registed event. + * + * @param array $events + * @return void */ public function removeEvents(array $events): void { @@ -159,6 +165,9 @@ trait HasEvents /** * Set observable mappings. + * + * @param array $observables + * @return self */ public function setObservables(array $observables): self { @@ -169,6 +178,8 @@ trait HasEvents /** * Get observable mappings. + * + * @return array */ public function getObservables(): array { @@ -177,6 +188,8 @@ trait HasEvents /** * Get the default events of Hyperf Database Model. + * + * @return array */ protected function getDefaultEvents(): array { From 374d8b2e3a450ff018f5834157995f6dee916704 Mon Sep 17 00:00:00 2001 From: Albert Chen Date: Mon, 19 Aug 2019 09:46:58 +0800 Subject: [PATCH 058/225] Fix class name for registered observer. --- src/database/src/Model/Concerns/HasEvents.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database/src/Model/Concerns/HasEvents.php b/src/database/src/Model/Concerns/HasEvents.php index f07030ff4..3d21b096f 100644 --- a/src/database/src/Model/Concerns/HasEvents.php +++ b/src/database/src/Model/Concerns/HasEvents.php @@ -99,7 +99,7 @@ trait HasEvents foreach ($this->getDefaultEvents() as $alias => $eventClass) { if (method_exists($class, $alias)) { - static::$observables[static::class][$alias] = $class; + static::$observables[static::class][$alias] = $className; } } } From 86d66d6bcdefe85c3e32d0339b4508e23d37bd51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 19 Aug 2019 09:57:40 +0800 Subject: [PATCH 059/225] Optimized code. --- src/websocket-server/src/ConfigProvider.php | 2 -- .../src/Listener/OnPipeMessageListener.php | 26 ++++++------------- src/websocket-server/src/Sender.php | 14 +++------- 3 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/websocket-server/src/ConfigProvider.php b/src/websocket-server/src/ConfigProvider.php index 47f1cc411..d31e94369 100644 --- a/src/websocket-server/src/ConfigProvider.php +++ b/src/websocket-server/src/ConfigProvider.php @@ -12,8 +12,6 @@ declare(strict_types=1); namespace Hyperf\WebSocketServer; -use Hyperf\WebSocketServer\Listener; - class ConfigProvider { public function __invoke(): array diff --git a/src/websocket-server/src/Listener/OnPipeMessageListener.php b/src/websocket-server/src/Listener/OnPipeMessageListener.php index d382e06c5..c13495671 100644 --- a/src/websocket-server/src/Listener/OnPipeMessageListener.php +++ b/src/websocket-server/src/Listener/OnPipeMessageListener.php @@ -12,16 +12,13 @@ declare(strict_types=1); namespace Hyperf\WebSocketServer\Listener; -use Hyperf\Contract\ConfigInterface; use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\Event\Contract\ListenerInterface; use Hyperf\ExceptionHandler\Formatter\FormatterInterface; use Hyperf\Framework\Event\OnPipeMessage; -use Hyperf\Server\ServerFactory; use Hyperf\WebSocketServer\Sender; use Hyperf\WebSocketServer\SenderPipeMessage; use Psr\Container\ContainerInterface; -use Swoole\Server; class OnPipeMessageListener implements ListenerInterface { @@ -30,21 +27,21 @@ class OnPipeMessageListener implements ListenerInterface */ private $container; - /** - * @var ConfigInterface - */ - private $config; - /** * @var StdoutLoggerInterface */ private $logger; - public function __construct(ContainerInterface $container, ConfigInterface $config, StdoutLoggerInterface $logger) + /** + * @var Sender + */ + private $sender; + + public function __construct(ContainerInterface $container, StdoutLoggerInterface $logger, Sender $sender) { $this->container = $container; - $this->config = $config; $this->logger = $logger; + $this->sender = $sender; } /** @@ -68,18 +65,11 @@ class OnPipeMessageListener implements ListenerInterface $message = $event->data; try { - $sender = $this->container->get(Sender::class); - - $sender->proxy($message->name, $message->arguments); + $this->sender->proxy($message->name, $message->arguments); } catch (\Throwable $exception) { $formatter = $this->container->get(FormatterInterface::class); $this->logger->warning($formatter->format($exception)); } } } - - protected function getServer(): Server - { - return $this->container->get(ServerFactory::class)->getServer()->getServer(); - } } diff --git a/src/websocket-server/src/Sender.php b/src/websocket-server/src/Sender.php index b5954575e..0486c0a1d 100644 --- a/src/websocket-server/src/Sender.php +++ b/src/websocket-server/src/Sender.php @@ -53,9 +53,6 @@ class Sender public function proxy(string $name, array $arguments): bool { $fd = $this->getFdFromProxyMethod($name, $arguments); - if ($fd === false) { - throw new InvalidMethodException($arguments); - } $result = $this->check($fd); if ($result) { @@ -82,16 +79,13 @@ class Sender return false; } - /** - * @return null|bool|int - */ - protected function getFdFromProxyMethod(string $method, array $arguments) + protected function getFdFromProxyMethod(string $method, array $arguments): int { - if (in_array($method, ['push', 'send', 'sendto'])) { - return $arguments[0]; + if (! in_array($method, ['push', 'send', 'sendto'])) { + throw new InvalidMethodException(sprintf('Method [%s] is not allowed.', $method)); } - return false; + return (int) $arguments[0]; } protected function getServer(): \Swoole\Server From df3ab346bfa70dcd4aec9e599595c222e9aa86af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 19 Aug 2019 14:45:51 +0800 Subject: [PATCH 060/225] Optimized code. --- src/server/src/ConfigProvider.php | 2 ++ src/server/src/SwooleServerFactory.php | 25 +++++++++++++++++++++++++ src/websocket-server/src/Sender.php | 10 +++++----- 3 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 src/server/src/SwooleServerFactory.php diff --git a/src/server/src/ConfigProvider.php b/src/server/src/ConfigProvider.php index 518e2a2a5..0deca9102 100644 --- a/src/server/src/ConfigProvider.php +++ b/src/server/src/ConfigProvider.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Hyperf\Server; use Hyperf\Server\Listener\InitProcessTitleListener; +use Swoole\Server; class ConfigProvider { @@ -20,6 +21,7 @@ class ConfigProvider { return [ 'dependencies' => [ + Server::class => SwooleServerFactory::class, ], 'commands' => [ ], diff --git a/src/server/src/SwooleServerFactory.php b/src/server/src/SwooleServerFactory.php new file mode 100644 index 000000000..3cc2d32a0 --- /dev/null +++ b/src/server/src/SwooleServerFactory.php @@ -0,0 +1,25 @@ +get(ServerFactory::class); + + return $factory->getServer()->getServer(); + } +} diff --git a/src/websocket-server/src/Sender.php b/src/websocket-server/src/Sender.php index 0486c0a1d..15c6e2e05 100644 --- a/src/websocket-server/src/Sender.php +++ b/src/websocket-server/src/Sender.php @@ -13,9 +13,9 @@ declare(strict_types=1); namespace Hyperf\WebSocketServer; use Hyperf\Contract\StdoutLoggerInterface; -use Hyperf\Server\ServerFactory; use Hyperf\WebSocketServer\Exception\InvalidMethodException; use Psr\Container\ContainerInterface; +use Swoole\Server; /** * @method push(int $fd, $data, int $opcode = null, $finish = null) @@ -23,12 +23,12 @@ use Psr\Container\ContainerInterface; class Sender { /** - * @var \Psr\Container\ContainerInterface + * @var ContainerInterface */ protected $container; /** - * @var \Hyperf\Contract\StdoutLoggerInterface + * @var StdoutLoggerInterface */ protected $logger; @@ -88,9 +88,9 @@ class Sender return (int) $arguments[0]; } - protected function getServer(): \Swoole\Server + protected function getServer(): Server { - return $this->container->get(ServerFactory::class)->getServer()->getServer(); + return $this->container->get(Server::class); } protected function sendPipeMessage(string $name, array $arguments): void From 58dc1bff18a3e0b3d0b89cc0db94a04b9d4d3b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Mon, 19 Aug 2019 14:50:17 +0800 Subject: [PATCH 061/225] Update ConfigProvider.php --- src/server/src/ConfigProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/src/ConfigProvider.php b/src/server/src/ConfigProvider.php index 0deca9102..449f30222 100644 --- a/src/server/src/ConfigProvider.php +++ b/src/server/src/ConfigProvider.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace Hyperf\Server; use Hyperf\Server\Listener\InitProcessTitleListener; -use Swoole\Server; +use Swoole\Server as SwooleServer; class ConfigProvider { @@ -21,7 +21,7 @@ class ConfigProvider { return [ 'dependencies' => [ - Server::class => SwooleServerFactory::class, + SwooleServer::class => SwooleServerFactory::class, ], 'commands' => [ ], From 4da9a5c15b9bc225a41945a88cae6804e483ceb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Mon, 19 Aug 2019 15:07:10 +0800 Subject: [PATCH 062/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac5f64ffd..276cd5192 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Added - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. -- [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Added `Sender` to fix fd not found when use method `server::send`. +- [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd ## Deleted From c79912b3e5150a1396a7826e0ae24ab1da30ad12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 19 Aug 2019 16:26:49 +0800 Subject: [PATCH 063/225] Update Server.php --- src/websocket-server/src/Server.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/websocket-server/src/Server.php b/src/websocket-server/src/Server.php index d76bd3eff..49af90ef6 100644 --- a/src/websocket-server/src/Server.php +++ b/src/websocket-server/src/Server.php @@ -24,7 +24,6 @@ use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpServer\MiddlewareManager; -use Hyperf\Server\ServerFactory; use Hyperf\Utils\Context; use Hyperf\WebSocketServer\Collector\FdCollector; use Hyperf\WebSocketServer\Exception\Handler\WebSocketExceptionHandler; @@ -35,6 +34,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Swoole\Http\Request as SwooleRequest; use Swoole\Http\Response as SwooleResponse; +use Swoole\Server as SwooleServer; use Swoole\Websocket\Frame; use Swoole\WebSocket\Server as WebSocketServer; @@ -96,7 +96,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On public function getServer(): WebSocketServer { - return $this->container->get(ServerFactory::class)->getServer()->getServer(); + return $this->container->get(SwooleServer::class); } public function onHandShake(SwooleRequest $request, SwooleResponse $response): void @@ -143,7 +143,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On } } - public function onMessage(\Swoole\Server $server, Frame $frame): void + public function onMessage(SwooleServer $server, Frame $frame): void { $fdObj = FdCollector::get($frame->fd); if (! $fdObj) { @@ -161,7 +161,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On $instance->onMessage($server, $frame); } - public function onClose(\Swoole\Server $server, int $fd, int $reactorId): void + public function onClose(SwooleServer $server, int $fd, int $reactorId): void { $this->logger->debug(sprintf('WebSocket: fd[%d] closed.', $fd)); From fe6e59cebb7983cbe538fe2bcc4f1857208207e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Mon, 19 Aug 2019 16:46:52 +0800 Subject: [PATCH 064/225] Update swoole-enterprise.md --- doc/zh/swoole-enterprise.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/swoole-enterprise.md b/doc/zh/swoole-enterprise.md index 3757b73fc..603780a81 100644 --- a/doc/zh/swoole-enterprise.md +++ b/doc/zh/swoole-enterprise.md @@ -116,7 +116,7 @@ ENTRYPOINT ["sh", ".build/entrypoint.sh"] ### 安装组件 ```bash -composer require hyperf/swoole-enterprise dev-master +composer require hyperf/swoole-enterprise ``` ## 使用 From b1492c1106b13f61550184cbf449579a21a40499 Mon Sep 17 00:00:00 2001 From: Albert Chen Date: Mon, 19 Aug 2019 21:58:08 +0800 Subject: [PATCH 065/225] Support multiple observers to one model at the same time. --- src/database/src/Model/Concerns/HasEvents.php | 7 ++++++- src/database/src/Model/Events/Event.php | 12 +++++++----- src/database/tests/ModelTest.php | 14 +++++++------- src/database/tests/Stubs/ModelObserverStub.php | 6 +++--- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/database/src/Model/Concerns/HasEvents.php b/src/database/src/Model/Concerns/HasEvents.php index 3d21b096f..15c712089 100644 --- a/src/database/src/Model/Concerns/HasEvents.php +++ b/src/database/src/Model/Concerns/HasEvents.php @@ -99,7 +99,12 @@ trait HasEvents foreach ($this->getDefaultEvents() as $alias => $eventClass) { if (method_exists($class, $alias)) { - static::$observables[static::class][$alias] = $className; + static::$observables[static::class][$alias] = array_unique( + array_merge( + static::$observables[static::class][$alias] ?? [], + [$className] + ) + ); } } } diff --git a/src/database/src/Model/Events/Event.php b/src/database/src/Model/Events/Event.php index 59c6981c4..304556134 100644 --- a/src/database/src/Model/Events/Event.php +++ b/src/database/src/Model/Events/Event.php @@ -42,11 +42,13 @@ abstract class Event implements StoppableEventInterface public function handle() { if (method_exists($this->getModel(), $this->getMethod())) { - return $this->getModel()->{$this->getMethod()}($this); + $this->getModel()->{$this->getMethod()}($this); } - if ($observerClass = $this->getObserverClass()) { - return make($observerClass)->{$this->getMethod()}($this->getModel()); + if ($observerClasses = $this->getObserverClasses()) { + foreach ($observerClasses as $observerClass) { + make($observerClass)->{$this->getMethod()}($this); + } } return $this; @@ -62,8 +64,8 @@ abstract class Event implements StoppableEventInterface return $this->model; } - public function getObserverClass(): ?string + public function getObserverClasses(): array { - return $this->getModel()->getObservables()[$this->getMethod()] ?? null; + return $this->getModel()->getObservables()[$this->getMethod()] ?? []; } } diff --git a/src/database/tests/ModelTest.php b/src/database/tests/ModelTest.php index 9650579c8..b1405fea7 100644 --- a/src/database/tests/ModelTest.php +++ b/src/database/tests/ModelTest.php @@ -1847,7 +1847,7 @@ class ModelTest extends TestCase { $model = new ModelStub(['id' => 1]); $model->setObservables($observables = [ - 'created' => 'ObserverClass' + 'created' => ['ObserverClass'] ]); $this->assertSame($observables, $model->getObservables()); @@ -1859,14 +1859,14 @@ class ModelTest extends TestCase $model = new ModelStub(['id' => 1]); - $this->assertSame(['updating' => ModelObserverStub::class], $model->getObservables()); + $this->assertSame(['updating' => [ModelObserverStub::class]], $model->getObservables()); } public function testClearObservables() { $model = new ModelStub(['id' => 1]); $model->setObservables($observables = [ - 'created' => 'ObserverClass' + 'created' => ['ObserverClass'] ]); ModelStub::clearObservables(); @@ -1874,18 +1874,18 @@ class ModelTest extends TestCase $this->assertSame([], $model->getObservables()); } - public function testGetObserverClassFromModelEvent() + public function testGetObserverClassesFromModelEvent() { $model = new ModelStub(['id' => 1]); $model->setObservables($observables = [ - 'updating' => 'ObserverClass' + 'updating' => ['ObserverClass'] ]); $saving = new Events\Saving($model, 'saving'); $updating = new Events\Updating($model, 'updating'); - $this->assertNull($saving->getObserverClass()); - $this->assertSame('ObserverClass', $updating->getObserverClass()); + $this->assertSame([], $saving->getObserverClasses()); + $this->assertSame(['ObserverClass'], $updating->getObserverClasses()); } public function testHandleModelObserver() diff --git a/src/database/tests/Stubs/ModelObserverStub.php b/src/database/tests/Stubs/ModelObserverStub.php index 7814fe8ea..1f988634d 100644 --- a/src/database/tests/Stubs/ModelObserverStub.php +++ b/src/database/tests/Stubs/ModelObserverStub.php @@ -12,12 +12,12 @@ declare(strict_types=1); namespace HyperfTest\Database\Stubs; -use Hyperf\Database\Model\Model; +use Hyperf\Database\Model\Events\Updating; class ModelObserverStub { - public function updating(Model $model) + public function updating(Updating $event) { - $model->foo = 'bar'; + $event->getModel()->foo = 'bar'; } } From f4341721cf92b0779b7bf95f438c9b5a21696706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 20 Aug 2019 11:49:24 +0800 Subject: [PATCH 066/225] Deleted TcpServerFactory. --- src/json-rpc/src/ConfigProvider.php | 1 - src/json-rpc/src/TcpServer.php | 12 +++++------- src/json-rpc/src/TcpServerFactory.php | 27 --------------------------- 3 files changed, 5 insertions(+), 35 deletions(-) delete mode 100644 src/json-rpc/src/TcpServerFactory.php diff --git a/src/json-rpc/src/ConfigProvider.php b/src/json-rpc/src/ConfigProvider.php index e1a5bb000..5bf155385 100644 --- a/src/json-rpc/src/ConfigProvider.php +++ b/src/json-rpc/src/ConfigProvider.php @@ -22,7 +22,6 @@ class ConfigProvider { return [ 'dependencies' => [ - TcpServer::class => TcpServerFactory::class, DataFormatter::class => DataFormatterFactory::class, ], 'commands' => [ diff --git a/src/json-rpc/src/TcpServer.php b/src/json-rpc/src/TcpServer.php index e23b7865d..59bab26c0 100644 --- a/src/json-rpc/src/TcpServer.php +++ b/src/json-rpc/src/TcpServer.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Hyperf\JsonRpc; use Hyperf\Contract\PackerInterface; +use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpMessage\Uri\Uri; @@ -25,7 +26,6 @@ use Hyperf\Server\ServerManager; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Log\LoggerInterface; use Swoole\Server as SwooleServer; class TcpServer extends Server @@ -40,13 +40,11 @@ class TcpServer extends Server */ protected $packer; - public function __construct( - ContainerInterface $container, - ProtocolManager $protocolManager, - LoggerInterface $logger - ) { - $dispatcher = $container->get(RequestDispatcher::class); + public function __construct(ContainerInterface $container, ProtocolManager $protocolManager) + { $protocol = new Protocol($container, $protocolManager, 'jsonrpc'); + $dispatcher = $container->get(RequestDispatcher::class); + $logger = $container->get(StdoutLoggerInterface::class); parent::__construct($container, $protocol, $dispatcher, $logger); diff --git a/src/json-rpc/src/TcpServerFactory.php b/src/json-rpc/src/TcpServerFactory.php deleted file mode 100644 index 10c7098e0..000000000 --- a/src/json-rpc/src/TcpServerFactory.php +++ /dev/null @@ -1,27 +0,0 @@ -get(StdoutLoggerInterface::class); - $protocolManager = $container->get(ProtocolManager::class); - return new TcpServer($container, $protocolManager, $logger); - } -} From b104120a65d077f28d87d0cc3ee3c83a6114f226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 20 Aug 2019 14:32:22 +0800 Subject: [PATCH 067/225] Optimized code. --- src/http-server/src/Server.php | 4 ++-- src/json-rpc/src/TcpServer.php | 4 +--- src/testing/src/Client.php | 3 ++- src/websocket-server/src/Server.php | 16 ++++++++-------- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/http-server/src/Server.php b/src/http-server/src/Server.php index 18ddc865c..c5fb13332 100644 --- a/src/http-server/src/Server.php +++ b/src/http-server/src/Server.php @@ -70,10 +70,10 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface */ protected $serverName; - public function __construct(ContainerInterface $container) + public function __construct(ContainerInterface $container, HttpDispatcher $dispatcher) { $this->container = $container; - $this->dispatcher = $container->get(HttpDispatcher::class); + $this->dispatcher = $dispatcher; } public function initCoreMiddleware(string $serverName): void diff --git a/src/json-rpc/src/TcpServer.php b/src/json-rpc/src/TcpServer.php index 59bab26c0..29b6d75e7 100644 --- a/src/json-rpc/src/TcpServer.php +++ b/src/json-rpc/src/TcpServer.php @@ -40,11 +40,9 @@ class TcpServer extends Server */ protected $packer; - public function __construct(ContainerInterface $container, ProtocolManager $protocolManager) + public function __construct(ContainerInterface $container, ProtocolManager $protocolManager, RequestDispatcher $dispatcher, StdoutLoggerInterface $logger) { $protocol = new Protocol($container, $protocolManager, 'jsonrpc'); - $dispatcher = $container->get(RequestDispatcher::class); - $logger = $container->get(StdoutLoggerInterface::class); parent::__construct($container, $protocol, $dispatcher, $logger); diff --git a/src/testing/src/Client.php b/src/testing/src/Client.php index b5cc086d8..72785268d 100644 --- a/src/testing/src/Client.php +++ b/src/testing/src/Client.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Hyperf\Testing; use Hyperf\Contract\PackerInterface; +use Hyperf\Dispatcher\HttpDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpMessage\Stream\SwooleStream; @@ -47,7 +48,7 @@ class Client extends Server public function __construct(ContainerInterface $container, PackerInterface $packer = null, $server = 'http') { - parent::__construct($container); + parent::__construct($container, $container->get(HttpDispatcher::class)); $this->packer = $packer ?? new JsonPacker(); $this->initCoreMiddleware($server); diff --git a/src/websocket-server/src/Server.php b/src/websocket-server/src/Server.php index 186f5003f..0d213b68e 100644 --- a/src/websocket-server/src/Server.php +++ b/src/websocket-server/src/Server.php @@ -77,11 +77,11 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On */ protected $serverName = 'websocket'; - public function __construct(ContainerInterface $container) + public function __construct(ContainerInterface $container, HttpDispatcher $dispatcher, StdoutLoggerInterface $logger) { $this->container = $container; - $this->dispatcher = $container->get(HttpDispatcher::class); - $this->logger = $container->get(StdoutLoggerInterface::class); + $this->dispatcher = $dispatcher; + $this->logger = $logger; } public function initCoreMiddleware(string $serverName): void @@ -129,7 +129,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On $class = $psr7Response->getAttribute('class'); - if (!empty($class)) { + if (! empty($class)) { FdCollector::set($request->fd, $class); defer(function () use ($request, $class) { @@ -145,7 +145,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On $psr7Response = $exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers); } finally { // Send the Response to client. - if (!$psr7Response || !$psr7Response instanceof Psr7Response) { + if (! $psr7Response || ! $psr7Response instanceof Psr7Response) { return; } $psr7Response->send(); @@ -155,14 +155,14 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On public function onMessage(SwooleServer $server, Frame $frame): void { $fdObj = FdCollector::get($frame->fd); - if (!$fdObj) { + if (! $fdObj) { $this->logger->warning(sprintf('WebSocket: fd[%d] does not exist.', $frame->fd)); return; } $instance = $this->container->get($fdObj->class); - if (!$instance instanceof OnMessageInterface) { + if (! $instance instanceof OnMessageInterface) { $this->logger->warning("{$instance} is not instanceof " . OnMessageInterface::class); return; } @@ -175,7 +175,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On $this->logger->debug(sprintf('WebSocket: fd[%d] closed.', $fd)); $fdObj = FdCollector::get($fd); - if (!$fdObj) { + if (! $fdObj) { return; } $instance = $this->container->get($fdObj->class); From 5bc77be58abde3c392eb8f8c3bc65344c4886e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Tue, 20 Aug 2019 15:12:29 +0800 Subject: [PATCH 068/225] Update CoreMiddleware.php --- src/websocket-server/src/CoreMiddleware.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/websocket-server/src/CoreMiddleware.php b/src/websocket-server/src/CoreMiddleware.php index 03cc318c6..d2c61ecef 100644 --- a/src/websocket-server/src/CoreMiddleware.php +++ b/src/websocket-server/src/CoreMiddleware.php @@ -35,7 +35,7 @@ class CoreMiddleware extends HttpCoreMiddleware $dispatched = $request->getAttribute(Dispatched::class); if (! $dispatched instanceof Dispatched) { - throw new ServerException('The object is not instanceof `HyperfHttpServerRouterDispatched`.'); + throw new ServerException(sprintf('The dispatched object is not a %s object.', Dispatched::class)); } switch ($dispatched->status) { From 5da8a07248240f98d3e434afb80fb207bf29ef46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 20 Aug 2019 15:50:14 +0800 Subject: [PATCH 069/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f211986a7..768426570 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ ## Deleted -- [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Deleted class `Hyperf\JsonRpc\HttpServerFactory`, `Hyperf\HttpServer\ServerFactory`. +- [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Deleted class `Hyperf\JsonRpc\HttpServerFactory`, `Hyperf\HttpServer\ServerFactory`, `Hyperf\GrpcServer\ServerFactory`. - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Deleted deprecated method `AsyncQueue::delay`. # v1.0.12 - TBD From 33bd9b2fcb6fdcf92ad47d2c3e8eae74fef4b104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 20 Aug 2019 17:19:50 +0800 Subject: [PATCH 070/225] Inject ExceptionHandlerDispatcher in construct. --- src/http-server/src/Server.php | 31 ++++++++++++++++------------ src/json-rpc/src/HttpServer.php | 12 +++++++---- src/json-rpc/src/TcpServer.php | 12 ++++++++--- src/rpc-server/src/Server.php | 32 +++++++++++++++++------------ src/testing/src/Client.php | 3 ++- src/websocket-server/src/Server.php | 17 +++++++++++---- 6 files changed, 69 insertions(+), 38 deletions(-) diff --git a/src/http-server/src/Server.php b/src/http-server/src/Server.php index c5fb13332..0b28bc66f 100644 --- a/src/http-server/src/Server.php +++ b/src/http-server/src/Server.php @@ -35,6 +35,21 @@ use Throwable; class Server implements OnRequestInterface, MiddlewareInitializerInterface { + /** + * @var \Psr\Container\ContainerInterface + */ + protected $container; + + /** + * @var HttpDispatcher + */ + protected $dispatcher; + + /** + * @var ExceptionHandlerDispatcher + */ + protected $exceptionHandlerDispatcher; + /** * @var array */ @@ -50,16 +65,6 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface */ protected $exceptionHandlers; - /** - * @var \Psr\Container\ContainerInterface - */ - protected $container; - - /** - * @var HttpDispatcher - */ - protected $dispatcher; - /** * @var Dispatcher */ @@ -70,10 +75,11 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface */ protected $serverName; - public function __construct(ContainerInterface $container, HttpDispatcher $dispatcher) + public function __construct(ContainerInterface $container, HttpDispatcher $dispatcher, ExceptionHandlerDispatcher $exceptionHandlerDispatcher) { $this->container = $container; $this->dispatcher = $dispatcher; + $this->exceptionHandlerDispatcher = $exceptionHandlerDispatcher; } public function initCoreMiddleware(string $serverName): void @@ -104,8 +110,7 @@ class Server implements OnRequestInterface, MiddlewareInitializerInterface $psr7Response = $this->dispatcher->dispatch($psr7Request, $middlewares, $this->coreMiddleware); } catch (Throwable $throwable) { // Delegate the exception to exception handler. - $exceptionHandlerDispatcher = $this->container->get(ExceptionHandlerDispatcher::class); - $psr7Response = $exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers); + $psr7Response = $this->exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers); } finally { // Send the Response to client. if (! isset($psr7Response) || ! $psr7Response instanceof Psr7Response) { diff --git a/src/json-rpc/src/HttpServer.php b/src/json-rpc/src/HttpServer.php index b51ad4caa..55304dd36 100644 --- a/src/json-rpc/src/HttpServer.php +++ b/src/json-rpc/src/HttpServer.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Hyperf\JsonRpc; +use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpServer\Contract\CoreMiddlewareInterface; @@ -45,10 +46,13 @@ class HttpServer extends Server */ protected $responseBuilder; - public function __construct(ContainerInterface $container, ProtocolManager $protocolManager) - { - $this->container = $container; - $this->dispatcher = $container->get(RequestDispatcher::class); + public function __construct( + ContainerInterface $container, + RequestDispatcher $dispatcher, + ExceptionHandlerDispatcher $exceptionHandlerDispatcher, + ProtocolManager $protocolManager + ) { + parent::__construct($container, $dispatcher, $exceptionHandlerDispatcher); $this->protocol = new Protocol($container, $protocolManager, 'jsonrpc-http'); $this->packer = $this->protocol->getPacker(); $this->responseBuilder = make(ResponseBuilder::class, [ diff --git a/src/json-rpc/src/TcpServer.php b/src/json-rpc/src/TcpServer.php index 29b6d75e7..6830a44a3 100644 --- a/src/json-rpc/src/TcpServer.php +++ b/src/json-rpc/src/TcpServer.php @@ -14,6 +14,7 @@ namespace Hyperf\JsonRpc; use Hyperf\Contract\PackerInterface; use Hyperf\Contract\StdoutLoggerInterface; +use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpMessage\Uri\Uri; @@ -40,11 +41,16 @@ class TcpServer extends Server */ protected $packer; - public function __construct(ContainerInterface $container, ProtocolManager $protocolManager, RequestDispatcher $dispatcher, StdoutLoggerInterface $logger) - { + public function __construct( + ContainerInterface $container, + RequestDispatcher $dispatcher, + ExceptionHandlerDispatcher $exceptionDispatcher, + ProtocolManager $protocolManager, + StdoutLoggerInterface $logger + ) { $protocol = new Protocol($container, $protocolManager, 'jsonrpc'); - parent::__construct($container, $protocol, $dispatcher, $logger); + parent::__construct($container, $dispatcher, $exceptionDispatcher, $protocol, $logger); $this->packer = $protocol->getPacker(); $this->responseBuilder = make(ResponseBuilder::class, [ diff --git a/src/rpc-server/src/Server.php b/src/rpc-server/src/Server.php index ebb8d0641..5c64ebe70 100644 --- a/src/rpc-server/src/Server.php +++ b/src/rpc-server/src/Server.php @@ -26,13 +26,27 @@ use Hyperf\Utils\Context; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Server\MiddlewareInterface; use Psr\Log\LoggerInterface; use Swoole\Server as SwooleServer; use Throwable; abstract class Server implements OnReceiveInterface, MiddlewareInitializerInterface { + /** + * @var ContainerInterface + */ + protected $container; + + /** + * @var DispatcherInterface + */ + protected $dispatcher; + + /** + * @var ExceptionHandlerDispatcher + */ + protected $exceptionHandlerDispatcher; + /** * @var array */ @@ -48,16 +62,6 @@ abstract class Server implements OnReceiveInterface, MiddlewareInitializerInterf */ protected $exceptionHandlers; - /** - * @var ContainerInterface - */ - protected $container; - - /** - * @var DispatcherInterface - */ - protected $dispatcher; - /** * @var string */ @@ -75,13 +79,15 @@ abstract class Server implements OnReceiveInterface, MiddlewareInitializerInterf public function __construct( ContainerInterface $container, - Protocol $protocol, DispatcherInterface $dispatcher, + ExceptionHandlerDispatcher $exceptionDispatcher, + Protocol $protocol, LoggerInterface $logger ) { $this->container = $container; - $this->protocol = $protocol; $this->dispatcher = $dispatcher; + $this->exceptionHandlerDispatcher = $exceptionDispatcher; + $this->protocol = $protocol; $this->logger = $logger; } diff --git a/src/testing/src/Client.php b/src/testing/src/Client.php index 72785268d..88a1ce632 100644 --- a/src/testing/src/Client.php +++ b/src/testing/src/Client.php @@ -14,6 +14,7 @@ namespace Hyperf\Testing; use Hyperf\Contract\PackerInterface; use Hyperf\Dispatcher\HttpDispatcher; +use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher; use Hyperf\HttpMessage\Server\Request as Psr7Request; use Hyperf\HttpMessage\Server\Response as Psr7Response; use Hyperf\HttpMessage\Stream\SwooleStream; @@ -48,7 +49,7 @@ class Client extends Server public function __construct(ContainerInterface $container, PackerInterface $packer = null, $server = 'http') { - parent::__construct($container, $container->get(HttpDispatcher::class)); + parent::__construct($container, $container->get(HttpDispatcher::class), $container->get(ExceptionHandlerDispatcher::class)); $this->packer = $packer ?? new JsonPacker(); $this->initCoreMiddleware($server); diff --git a/src/websocket-server/src/Server.php b/src/websocket-server/src/Server.php index 0d213b68e..1ee927f2f 100644 --- a/src/websocket-server/src/Server.php +++ b/src/websocket-server/src/Server.php @@ -52,6 +52,11 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On */ protected $dispatcher; + /** + * @var ExceptionHandlerDispatcher + */ + protected $exceptionHandlerDispatcher; + /** * @var CoreMiddlewareInterface */ @@ -77,10 +82,15 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On */ protected $serverName = 'websocket'; - public function __construct(ContainerInterface $container, HttpDispatcher $dispatcher, StdoutLoggerInterface $logger) - { + public function __construct( + ContainerInterface $container, + HttpDispatcher $dispatcher, + ExceptionHandlerDispatcher $exceptionHandlerDispatcher, + StdoutLoggerInterface $logger + ) { $this->container = $container; $this->dispatcher = $dispatcher; + $this->exceptionHandlerDispatcher = $exceptionHandlerDispatcher; $this->logger = $logger; } @@ -141,8 +151,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On } } catch (\Throwable $throwable) { // Delegate the exception to exception handler. - $exceptionHandlerDispatcher = $this->container->get(ExceptionHandlerDispatcher::class); - $psr7Response = $exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers); + $psr7Response = $this->exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers); } finally { // Send the Response to client. if (! $psr7Response || ! $psr7Response instanceof Psr7Response) { From 2f0bba5ba4c5956c3a924642889fbff69046a176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Tue, 20 Aug 2019 17:34:38 +0800 Subject: [PATCH 071/225] Update Server.php --- src/http-server/src/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http-server/src/Server.php b/src/http-server/src/Server.php index 0b28bc66f..7cc447906 100644 --- a/src/http-server/src/Server.php +++ b/src/http-server/src/Server.php @@ -36,7 +36,7 @@ use Throwable; class Server implements OnRequestInterface, MiddlewareInitializerInterface { /** - * @var \Psr\Container\ContainerInterface + * @var ContainerInterface */ protected $container; From 1faec5f7f5458c7a09e970d43453475a649b7f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Tue, 20 Aug 2019 18:35:48 +0800 Subject: [PATCH 072/225] Update circuit-breaker.md --- doc/zh/circuit-breaker.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/zh/circuit-breaker.md b/doc/zh/circuit-breaker.md index 49af67dfd..f9d740821 100644 --- a/doc/zh/circuit-breaker.md +++ b/doc/zh/circuit-breaker.md @@ -13,15 +13,15 @@ composer require hyperf/circuit-breaker ## 使用熔断器 熔断器的使用十分简单,只需要加入 `Hyperf\CircuitBreaker\Annotation\CircuitBreaker` 注解,就可以根据规定策略,进行熔断。 -比如我们需要到另外服务中查询用户列表,用户列表需要关联很多的表,查询效率较低,但平常并发量不高的时候,相应速度还说得过去。一旦并发量激增,就会导致响应速度变慢,并会使对方服务出现慢查。这个时候,我们只需要配置一下熔断超时时间 `timeout` 为 0.05 秒,失败计数 `failCounter` 超过 1 次后熔断,相应 `fallback` 为 `App\UserService` 类的 `searchFallback` 方法。这样当响应超时并触发熔断后,就不会再请求对端的服务了,而是直接将服务降级从当前项目中返回数据,即根据 `fallback` 指定的方法来进行返回。 +比如我们需要到另外服务中查询用户列表,用户列表需要关联很多的表,查询效率较低,但平常并发量不高的时候,相应速度还说得过去。一旦并发量激增,就会导致响应速度变慢,并会使对方服务出现慢查。这个时候,我们只需要配置一下熔断超时时间 `timeout` 为 0.05 秒,失败计数 `failCounter` 超过 1 次后熔断,相应 `fallback` 为 `App\Service\UserService` 类的 `searchFallback` 方法。这样当响应超时并触发熔断后,就不会再请求对端的服务了,而是直接将服务降级从当前项目中返回数据,即根据 `fallback` 指定的方法来进行返回。 ```php Date: Tue, 20 Aug 2019 19:45:42 +0800 Subject: [PATCH 073/225] Added model-observer component. --- src/model-observer/.gitattributes | 1 + src/model-observer/LICENSE.md | 9 +++ src/model-observer/composer.json | 58 ++++++++++++++++ .../src/Annotation/Observer.php | 35 ++++++++++ .../src/Collector/ObserverCollector.php | 49 ++++++++++++++ src/model-observer/src/ConfigProvider.php | 31 +++++++++ .../src/Listener/ModelEventListener.php | 66 +++++++++++++++++++ 7 files changed, 249 insertions(+) create mode 100644 src/model-observer/.gitattributes create mode 100644 src/model-observer/LICENSE.md create mode 100644 src/model-observer/composer.json create mode 100644 src/model-observer/src/Annotation/Observer.php create mode 100644 src/model-observer/src/Collector/ObserverCollector.php create mode 100644 src/model-observer/src/ConfigProvider.php create mode 100644 src/model-observer/src/Listener/ModelEventListener.php diff --git a/src/model-observer/.gitattributes b/src/model-observer/.gitattributes new file mode 100644 index 000000000..bdd4ea29c --- /dev/null +++ b/src/model-observer/.gitattributes @@ -0,0 +1 @@ +/tests export-ignore \ No newline at end of file diff --git a/src/model-observer/LICENSE.md b/src/model-observer/LICENSE.md new file mode 100644 index 000000000..eb14702a3 --- /dev/null +++ b/src/model-observer/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) Hyperf + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/model-observer/composer.json b/src/model-observer/composer.json new file mode 100644 index 000000000..ca69cacb7 --- /dev/null +++ b/src/model-observer/composer.json @@ -0,0 +1,58 @@ +{ + "name": "hyperf/model-observer", + "description": "A model observer for Hyperf.", + "license": "MIT", + "keywords": [ + "php", + "swoole", + "hyperf", + "model-observer" + ], + "support": { + }, + "require": { + "php": ">=7.2", + "hyperf/contract": "~1.1.0", + "hyperf/database": "~1.1.0", + "hyperf/di": "~1.1.0", + "hyperf/utils": "~1.1.0", + "psr/container": "^1.0", + "psr/log": "^1.0", + "psr/event-dispatcher": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.9", + "malukenho/docheader": "^0.1.6", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.0" + }, + "suggest": { + }, + "autoload": { + "psr-4": { + "Hyperf\\ModelObserver\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "HyperfTest\\ModelObserver\\": "tests/" + } + }, + "config": { + "sort-packages": true + }, + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + }, + "hyperf": { + "config": "Hyperf\\ModelObserver\\ConfigProvider" + } + }, + "bin": [ + ], + "scripts": { + "cs-fix": "php-cs-fixer fix $1", + "test": "phpunit --colors=always" + } +} diff --git a/src/model-observer/src/Annotation/Observer.php b/src/model-observer/src/Annotation/Observer.php new file mode 100644 index 000000000..0660d6233 --- /dev/null +++ b/src/model-observer/src/Annotation/Observer.php @@ -0,0 +1,35 @@ +model, $className); + } +} diff --git a/src/model-observer/src/Collector/ObserverCollector.php b/src/model-observer/src/Collector/ObserverCollector.php new file mode 100644 index 000000000..c2a8c1889 --- /dev/null +++ b/src/model-observer/src/Collector/ObserverCollector.php @@ -0,0 +1,49 @@ + [ + ], + 'commands' => [ + ], + 'scan' => [ + 'paths' => [ + __DIR__, + ], + ], + ]; + } +} diff --git a/src/model-observer/src/Listener/ModelEventListener.php b/src/model-observer/src/Listener/ModelEventListener.php new file mode 100644 index 000000000..343bd988d --- /dev/null +++ b/src/model-observer/src/Listener/ModelEventListener.php @@ -0,0 +1,66 @@ +container = $container; + } + + public function listen(): array + { + return [ + Event::class, + ]; + } + + /** + * @param Event $event + * @return Event + */ + public function process(object $event) + { + $model = $event->getModel(); + $modelName = get_class($model); + + $observers = ObserverCollector::getObservables($modelName); + foreach ($observers as $name) { + if (! $this->container->has($name)) { + continue; + } + + $observer = $this->container->get($name); + if (method_exists($observer, $event->getMethod())) { + $observer->{$event->getMethod()}($event); + } + } + + return $event; + } +} From eae97861841fe1eed2ee6a74ac390f3a122afa80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 20 Aug 2019 19:47:00 +0800 Subject: [PATCH 074/225] Update composer.json --- src/model-observer/composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model-observer/composer.json b/src/model-observer/composer.json index ca69cacb7..f2256b20c 100644 --- a/src/model-observer/composer.json +++ b/src/model-observer/composer.json @@ -17,8 +17,8 @@ "hyperf/di": "~1.1.0", "hyperf/utils": "~1.1.0", "psr/container": "^1.0", - "psr/log": "^1.0", - "psr/event-dispatcher": "^1.0" + "psr/event-dispatcher": "^1.0", + "psr/log": "^1.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.9", From e8fb6c8535c3d12a7c1dbe3795d2315a03a6ae3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Wed, 21 Aug 2019 14:16:07 +0800 Subject: [PATCH 075/225] Update middleware.md --- doc/zh/middleware/middleware.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/middleware/middleware.md b/doc/zh/middleware/middleware.md index 18ed5dd2d..0522ca59d 100644 --- a/doc/zh/middleware/middleware.md +++ b/doc/zh/middleware/middleware.md @@ -221,7 +221,7 @@ class FooMiddleware implements MiddlewareInterface ## 中间件的执行顺序 -我们从上面可以了解到总共有 `3` 种级别的中间件,分别为 `全局中间件`、`类级别中间件`、`方法级别中间件`,如果都定义了这些中间件,执行顺序为:`全局中间件 -> 方法级别中间件 -> 类级别中间件`。 +我们从上面可以了解到总共有 `3` 种级别的中间件,分别为 `全局中间件`、`类级别中间件`、`方法级别中间件`,如果都定义了这些中间件,执行顺序为:`全局中间件 -> 类级别中间件 -> 方法级别中间件`。 ## 全局更改请求和响应对象 From 9477b380a42ced11f94b8514479521bed02cf50c Mon Sep 17 00:00:00 2001 From: xiabin <276147613@qq.com> Date: Wed, 21 Aug 2019 17:02:39 +0800 Subject: [PATCH 076/225] Update aop.md --- doc/zh/aop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/aop.md b/doc/zh/aop.md index f832c22ab..bdb26b752 100644 --- a/doc/zh/aop.md +++ b/doc/zh/aop.md @@ -64,7 +64,7 @@ class FooAspect extends AbstractAspect ## 代理类缓存 -所有被 AOP 影响的类,都会在 `./runtime/container/proxy/` 文件夹内生成对应的 `代理类缓存`,服务启动时,如果类所对应的代理类缓存存在,则不会重新生成直接使用缓存,即时 `Aspect` 的切入范围发生了改变。不存在时,则会自动重新生成新的代理类缓存。 +所有被 AOP 影响的类,都会在 `./runtime/container/proxy/` 文件夹内生成对应的 `代理类缓存`,服务启动时,如果类所对应的代理类缓存存在,则不会重新生成直接使用缓存,即使 `Aspect` 的切入范围发生了改变。不存在时,则会自动重新生成新的代理类缓存。 在部署生产环境时,我们可能会希望 Hyperf 提前将所有代理类提前生成,而不是使用时动态的生成,可以通过 `php bin/hyperf.php di:init-proxy` 命令来生成所有代理类,该命令会忽视现有的代理类缓存,全部重新生成。 From 0898943f1256a031e2ba63370eab05a79d6aca49 Mon Sep 17 00:00:00 2001 From: Agnes <1114145341@qq.com> Date: Wed, 21 Aug 2019 21:57:38 +0800 Subject: [PATCH 077/225] Fixed bug. --- src/testing/src/Client.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/testing/src/Client.php b/src/testing/src/Client.php index 88a1ce632..c510e750c 100644 --- a/src/testing/src/Client.php +++ b/src/testing/src/Client.php @@ -21,6 +21,7 @@ use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\HttpMessage\Upload\UploadedFile; use Hyperf\HttpMessage\Uri\Uri; use Hyperf\HttpServer\MiddlewareManager; +use Hyperf\HttpServer\Router\Dispatched; use Hyperf\HttpServer\Server; use Hyperf\Utils\Arr; use Hyperf\Utils\Context; @@ -118,7 +119,14 @@ class Client extends Server */ [$psr7Request, $psr7Response] = $this->init($method, $path, $options); - $middlewares = array_merge($this->middlewares, MiddlewareManager::get($this->serverName, $psr7Request->getUri()->getPath(), $psr7Request->getMethod())); + $psr7Request = $this->coreMiddleware->dispatch($psr7Request); + /** @var Dispatched $dispatched */ + $dispatched = $psr7Request->getAttribute(Dispatched::class); + $middlewares = $this->middlewares; + if ($dispatched->isFound()) { + $registedMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod()); + $middlewares = array_merge($middlewares, $registedMiddlewares); + } return $this->dispatcher->dispatch($psr7Request, $middlewares, $this->coreMiddleware); } From ab66c7e2601e1f38f811ecdd08858a9055387bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 09:41:29 +0800 Subject: [PATCH 078/225] Added testing. --- composer.json | 1 + src/testing/.gitattributes | 1 + src/testing/composer.json | 1 + src/testing/tests/ClientTest.php | 67 ++++++++++++++++++++++++ src/testing/tests/Stub/FooController.php | 21 ++++++++ 5 files changed, 91 insertions(+) create mode 100644 src/testing/.gitattributes create mode 100644 src/testing/tests/ClientTest.php create mode 100644 src/testing/tests/Stub/FooController.php diff --git a/composer.json b/composer.json index b8b5df5fc..4135c5b63 100644 --- a/composer.json +++ b/composer.json @@ -201,6 +201,7 @@ "HyperfTest\\ServiceGovernance\\": "src/service-governance/tests/", "HyperfTest\\Snowflake\\": "src/snowflake/tests/", "HyperfTest\\Task\\": "src/task/tests/", + "HyperfTest\\Testing\\": "src/testing/tests/", "HyperfTest\\Utils\\": "src/utils/tests/", "HyperfTest\\WebSocketClient\\": "src/websocket-client/tests/" } diff --git a/src/testing/.gitattributes b/src/testing/.gitattributes new file mode 100644 index 000000000..bdd4ea29c --- /dev/null +++ b/src/testing/.gitattributes @@ -0,0 +1 @@ +/tests export-ignore \ No newline at end of file diff --git a/src/testing/composer.json b/src/testing/composer.json index 8f8f9409d..d7801c4c4 100644 --- a/src/testing/composer.json +++ b/src/testing/composer.json @@ -15,6 +15,7 @@ }, "autoload-dev": { "psr-4": { + "HyperfTest\\Testing\\": "tests/" } }, "require": { diff --git a/src/testing/tests/ClientTest.php b/src/testing/tests/ClientTest.php new file mode 100644 index 000000000..98dbcf048 --- /dev/null +++ b/src/testing/tests/ClientTest.php @@ -0,0 +1,67 @@ +getContainer(); + + $client = new Client($container); + + $data = $client->get('/'); + + $this->assertSame(0, $data['code']); + $this->assertSame('Hello Hyperf!', $data['data']); + } + + public function getContainer() + { + $container = Mockery::mock(ContainerInterface::class); + + $container->shouldReceive('get')->with(HttpDispatcher::class)->andReturn(new HttpDispatcher($container)); + $container->shouldReceive('get')->with(ExceptionHandlerDispatcher::class)->andReturn(new ExceptionHandlerDispatcher($container)); + $container->shouldReceive('get')->with(DispatcherFactory::class)->andReturn($factory = new DispatcherFactory()); + $container->shouldReceive('get')->with(NormalizerInterface::class)->andReturn(new SimpleNormalizer()); + $container->shouldReceive('get')->with(MethodDefinitionCollectorInterface::class)->andReturn(new MethodDefinitionCollector()); + $container->shouldReceive('get')->with(ConfigInterface::class)->andReturn(new Config([])); + $container->shouldReceive('get')->with(Filesystem::class)->andReturn(new Filesystem()); + $container->shouldReceive('get')->with(FooController::class)->andReturn(new FooController()); + + Router::init($factory); + Router::get('/', [FooController::class, 'index']); + return $container; + } +} diff --git a/src/testing/tests/Stub/FooController.php b/src/testing/tests/Stub/FooController.php new file mode 100644 index 000000000..e3c76e2c3 --- /dev/null +++ b/src/testing/tests/Stub/FooController.php @@ -0,0 +1,21 @@ + 0, 'data' => 'Hello Hyperf!']; + } +} From 5ef6e8106da35fb8f16c38045b175d35fa60d805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 09:55:12 +0800 Subject: [PATCH 079/225] Fixed `Hyperf\Testing\Client` would throw a exception not handle exception handlers. --- CHANGELOG.md | 4 +++ src/testing/src/Client.php | 9 ++++- src/testing/tests/ClientTest.php | 27 ++++++++++++++- .../Exception/Handler/FooExceptionHandler.php | 33 +++++++++++++++++++ src/testing/tests/Stub/FooController.php | 5 +++ 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 src/testing/tests/Stub/Exception/Handler/FooExceptionHandler.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b8ce7444..6740ae136 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. - [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd +## Fixed + +- [#437](https://github.com/hyperf-cloud/hyperf/pull/437) Fixed `Hyperf\Testing\Client` would throw a exception not handle exception handlers. + ## Deleted - [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Deleted class `Hyperf\JsonRpc\HttpServerFactory`, `Hyperf\HttpServer\ServerFactory`, `Hyperf\GrpcServer\ServerFactory`. diff --git a/src/testing/src/Client.php b/src/testing/src/Client.php index c510e750c..247156962 100644 --- a/src/testing/src/Client.php +++ b/src/testing/src/Client.php @@ -128,7 +128,14 @@ class Client extends Server $middlewares = array_merge($middlewares, $registedMiddlewares); } - return $this->dispatcher->dispatch($psr7Request, $middlewares, $this->coreMiddleware); + try { + $psr7Response = $this->dispatcher->dispatch($psr7Request, $middlewares, $this->coreMiddleware); + } catch (\Throwable $throwable) { + // Delegate the exception to exception handler. + $psr7Response = $this->exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers); + } + + return $psr7Response; } protected function init(string $method, string $path, array $options = []): array diff --git a/src/testing/tests/ClientTest.php b/src/testing/tests/ClientTest.php index 98dbcf048..566d40098 100644 --- a/src/testing/tests/ClientTest.php +++ b/src/testing/tests/ClientTest.php @@ -24,6 +24,7 @@ use Hyperf\HttpServer\Router\Router; use Hyperf\Testing\Client; use Hyperf\Utils\Filesystem\Filesystem; use Hyperf\Utils\Serializer\SimpleNormalizer; +use HyperfTest\Testing\Stub\Exception\Handler\FooExceptionHandler; use HyperfTest\Testing\Stub\FooController; use Mockery; use PHPUnit\Framework\TestCase; @@ -47,6 +48,18 @@ class ClientTest extends TestCase $this->assertSame('Hello Hyperf!', $data['data']); } + public function testClientException() + { + $container = $this->getContainer(); + + $client = new Client($container); + + $data = $client->get('/exception'); + + $this->assertSame(500, $data['code']); + $this->assertSame('Server Error', $data['message']); + } + public function getContainer() { $container = Mockery::mock(ContainerInterface::class); @@ -56,12 +69,24 @@ class ClientTest extends TestCase $container->shouldReceive('get')->with(DispatcherFactory::class)->andReturn($factory = new DispatcherFactory()); $container->shouldReceive('get')->with(NormalizerInterface::class)->andReturn(new SimpleNormalizer()); $container->shouldReceive('get')->with(MethodDefinitionCollectorInterface::class)->andReturn(new MethodDefinitionCollector()); - $container->shouldReceive('get')->with(ConfigInterface::class)->andReturn(new Config([])); + $container->shouldReceive('get')->with(ConfigInterface::class)->andReturn(new Config([ + 'exceptions' => [ + 'handler' => [ + 'http' => [ + FooExceptionHandler::class, + ], + ], + ], + ])); $container->shouldReceive('get')->with(Filesystem::class)->andReturn(new Filesystem()); $container->shouldReceive('get')->with(FooController::class)->andReturn(new FooController()); + $container->shouldReceive('has')->andReturn(true); + $container->shouldReceive('get')->with(FooExceptionHandler::class)->andReturn(new FooExceptionHandler()); Router::init($factory); Router::get('/', [FooController::class, 'index']); + Router::get('/exception', [FooController::class, 'exception']); + return $container; } } diff --git a/src/testing/tests/Stub/Exception/Handler/FooExceptionHandler.php b/src/testing/tests/Stub/Exception/Handler/FooExceptionHandler.php new file mode 100644 index 000000000..8a8386d54 --- /dev/null +++ b/src/testing/tests/Stub/Exception/Handler/FooExceptionHandler.php @@ -0,0 +1,33 @@ + $throwable->getCode(), 'message' => $throwable->getMessage()]; + + return $response->withBody(new SwooleStream(json_encode($data))); + } + + public function isValid(Throwable $throwable): bool + { + return true; + } +} diff --git a/src/testing/tests/Stub/FooController.php b/src/testing/tests/Stub/FooController.php index e3c76e2c3..7d3984710 100644 --- a/src/testing/tests/Stub/FooController.php +++ b/src/testing/tests/Stub/FooController.php @@ -18,4 +18,9 @@ class FooController { return ['code' => 0, 'data' => 'Hello Hyperf!']; } + + public function exception() + { + throw new \RuntimeException('Server Error', 500); + } } From c249473b66af2ba0aa30054d1b2a54b920323c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 09:57:54 +0800 Subject: [PATCH 080/225] Update --- CHANGELOG.md | 4 ++-- phpunit.xml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6740ae136..89610c335 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,9 @@ - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. - [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd -## Fixed +## Changed -- [#437](https://github.com/hyperf-cloud/hyperf/pull/437) Fixed `Hyperf\Testing\Client` would throw a exception not handle exception handlers. +- [#437](https://github.com/hyperf-cloud/hyperf/pull/437) Changed `Hyperf\Testing\Client` handle exception handlers instead of throw an exception directly. ## Deleted diff --git a/phpunit.xml b/phpunit.xml index 445a54672..34536acba 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -36,6 +36,7 @@ ./src/service-governance/tests ./src/snowflake/tests ./src/task/tests + ./src/testing/tests ./src/utils/tests ./src/websocket-client/tests From 0847376e26dd9e104448044893667e92a0633030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 18:29:37 +0800 Subject: [PATCH 081/225] Added default frequency. --- src/db-connection/src/Frequency.php | 78 +---------------------- src/pool/.gitattributes | 1 + src/pool/src/Frequency.php | 92 +++++++++++++++++++++++++++ src/pool/tests/FrequencyTest.php | 75 ++++++++++++++++++++++ src/pool/tests/Stub/FrequencyStub.php | 33 ++++++++++ src/redis/src/Frequency.php | 19 ++++++ src/redis/src/Pool/RedisPool.php | 3 + src/redis/src/RedisConnection.php | 2 + 8 files changed, 227 insertions(+), 76 deletions(-) create mode 100644 src/pool/.gitattributes create mode 100644 src/pool/src/Frequency.php create mode 100644 src/pool/tests/FrequencyTest.php create mode 100644 src/pool/tests/Stub/FrequencyStub.php create mode 100644 src/redis/src/Frequency.php diff --git a/src/db-connection/src/Frequency.php b/src/db-connection/src/Frequency.php index 73f31ae47..c6e7987a7 100644 --- a/src/db-connection/src/Frequency.php +++ b/src/db-connection/src/Frequency.php @@ -12,82 +12,8 @@ declare(strict_types=1); namespace Hyperf\DbConnection; -use Hyperf\Contract\FrequencyInterface; -use Hyperf\Pool\LowFrequencyInterface; +use Hyperf\Pool\Frequency as DefaultFrequency; -class Frequency implements FrequencyInterface, LowFrequencyInterface +class Frequency extends DefaultFrequency { - /** - * @var array - */ - protected $hits = []; - - /** - * How much time do you want to calculate the frequency ? - * @var int - */ - protected $time = 10; - - /** - * @var int - */ - protected $lowFrequency = 5; - - /** - * @var int - */ - protected $beginTime; - - public function __construct() - { - $this->beginTime = time(); - } - - public function hit(int $number = 1): bool - { - $this->flush(); - - $now = time(); - $hit = $this->hits[$now] ?? 0; - $this->hits[$now] = $number + $hit; - - return true; - } - - public function frequency(): float - { - $this->flush(); - - $hits = 0; - $count = 0; - foreach ($this->hits as $hit) { - ++$count; - $hits += $hit; - } - - return floatval($hits / $count); - } - - public function isLowFrequency(): bool - { - return $this->frequency() < $this->lowFrequency; - } - - protected function flush(): void - { - $now = time(); - $latest = $now - $this->time; - foreach ($this->hits as $time => $hit) { - if ($time < $latest) { - unset($this->hits[$time]); - } - } - - if (count($this->hits) < $this->time) { - $beginTime = $this->beginTime < $latest ? $latest : $this->beginTime; - for ($i = $beginTime; $i < $now; ++$i) { - $this->hits[$i] = $this->hits[$i] ?? 0; - } - } - } } diff --git a/src/pool/.gitattributes b/src/pool/.gitattributes new file mode 100644 index 000000000..bdd4ea29c --- /dev/null +++ b/src/pool/.gitattributes @@ -0,0 +1 @@ +/tests export-ignore \ No newline at end of file diff --git a/src/pool/src/Frequency.php b/src/pool/src/Frequency.php new file mode 100644 index 000000000..8908ea4f7 --- /dev/null +++ b/src/pool/src/Frequency.php @@ -0,0 +1,92 @@ +beginTime = time(); + } + + public function hit(int $number = 1): bool + { + $this->flush(); + + $now = time(); + $hit = $this->hits[$now] ?? 0; + $this->hits[$now] = $number + $hit; + + return true; + } + + public function frequency(): float + { + $this->flush(); + + $hits = 0; + $count = 0; + foreach ($this->hits as $hit) { + ++$count; + $hits += $hit; + } + + return floatval($hits / $count); + } + + public function isLowFrequency(): bool + { + return $this->frequency() < $this->lowFrequency; + } + + protected function flush(): void + { + $now = time(); + $latest = $now - $this->time; + foreach ($this->hits as $time => $hit) { + if ($time < $latest) { + unset($this->hits[$time]); + } + } + + if (count($this->hits) < $this->time) { + $beginTime = max($this->beginTime, $latest); + for ($i = $beginTime; $i < $now; ++$i) { + $this->hits[$i] = $this->hits[$i] ?? 0; + } + } + } +} diff --git a/src/pool/tests/FrequencyTest.php b/src/pool/tests/FrequencyTest.php new file mode 100644 index 000000000..94a482906 --- /dev/null +++ b/src/pool/tests/FrequencyTest.php @@ -0,0 +1,75 @@ +setBeginTime($now - 4); + $frequency->setHits([ + $now => 1, + $now - 1 => 10, + $now - 2 => 10, + $now - 3 => 10, + $now - 4 => 10, + ]); + + $num = $frequency->frequency(); + $this->assertSame(41 / 5, $num); + + $frequency->hit(); + $num = $frequency->frequency(); + $this->assertSame(42 / 5, $num); + } + + public function testFrequencyHitOneSecondAfter() + { + $frequency = new FrequencyStub(); + $now = time(); + + $frequency->setBeginTime($now - 4); + $frequency->setHits([ + $now => 1, + $now - 1 => 10, + $now - 2 => 10, + $now - 4 => 10, + ]); + $num = $frequency->frequency(); + $this->assertSame(31 / 5, $num); + $frequency->hit(); + $num = $frequency->frequency(); + $this->assertSame(32 / 5, $num); + + $frequency->setHits([ + $now => 1, + $now - 1 => 10, + $now - 2 => 10, + $now - 3 => 10, + ]); + $num = $frequency->frequency(); + $this->assertSame(31 / 5, $num); + $frequency->hit(); + $num = $frequency->frequency(); + $this->assertSame(32 / 5, $num); + } +} diff --git a/src/pool/tests/Stub/FrequencyStub.php b/src/pool/tests/Stub/FrequencyStub.php new file mode 100644 index 000000000..a6eed5929 --- /dev/null +++ b/src/pool/tests/Stub/FrequencyStub.php @@ -0,0 +1,33 @@ +beginTime = $time; + } + + public function setHits($hits) + { + $this->hits = $hits; + } + + public function getHits() + { + return $this->hits; + } +} diff --git a/src/redis/src/Frequency.php b/src/redis/src/Frequency.php new file mode 100644 index 000000000..6d331514d --- /dev/null +++ b/src/redis/src/Frequency.php @@ -0,0 +1,19 @@ +config = $config->get($key); $options = Arr::get($this->config, 'pool', []); + $this->frequency = make(Frequency::class); + parent::__construct($container, $options); } diff --git a/src/redis/src/RedisConnection.php b/src/redis/src/RedisConnection.php index 7cb3b3ef6..97a68a8b5 100644 --- a/src/redis/src/RedisConnection.php +++ b/src/redis/src/RedisConnection.php @@ -98,6 +98,8 @@ class RedisConnection extends BaseConnection implements ConnectionInterface public function close(): bool { + unset($this->connection); + return true; } From c90d16fd0c8508411c72481404bee62c0c4a2bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 18:41:38 +0800 Subject: [PATCH 082/225] Added testing. --- src/redis/tests/RedisConnectionTest.php | 43 ++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/redis/tests/RedisConnectionTest.php b/src/redis/tests/RedisConnectionTest.php index 0ea2074c9..85f42c90b 100644 --- a/src/redis/tests/RedisConnectionTest.php +++ b/src/redis/tests/RedisConnectionTest.php @@ -15,6 +15,11 @@ namespace HyperfTest\Redis; use Hyperf\Config\Config; use Hyperf\Contract\ConfigInterface; use Hyperf\Di\Container; +use Hyperf\Pool\Channel; +use Hyperf\Pool\LowFrequencyInterface; +use Hyperf\Pool\PoolOption; +use Hyperf\Redis\Frequency; +use Hyperf\Utils\ApplicationContext; use HyperfTest\Redis\Stub\RedisPoolStub; use Mockery; use PHPUnit\Framework\TestCase; @@ -69,10 +74,33 @@ class RedisConnectionTest extends TestCase $this->assertSame(null, $connection->getDatabase()); } + public function testRedisCloseInLowFrequency() + { + $pool = $this->getRedisPool(); + + $connection1 = $pool->get()->getConnection(); + $connection2 = $pool->get()->getConnection(); + $connection3 = $pool->get()->getConnection(); + + $this->assertSame(3, $pool->getCurrentConnections()); + + $connection1->release(); + $connection2->release(); + $connection3->release(); + + $this->assertSame(3, $pool->getCurrentConnections()); + + $connection = $pool->get()->getConnection(); + + $this->assertSame(1, $pool->getCurrentConnections()); + + $connection->release(); + } + private function getRedisPool() { $container = Mockery::mock(Container::class); - $container->shouldReceive('get')->once()->with(ConfigInterface::class)->andReturn(new Config([ + $container->shouldReceive('get')->with(ConfigInterface::class)->andReturn(new Config([ 'redis' => [ 'default' => [ 'host' => 'redis', @@ -90,6 +118,19 @@ class RedisConnectionTest extends TestCase ], ])); + $frequency = Mockery::mock(LowFrequencyInterface::class); + $frequency->shouldReceive('isLowFrequency')->andReturn(true); + + $container->shouldReceive('make')->with(Frequency::class, Mockery::any())->andReturn($frequency); + $container->shouldReceive('make')->with(PoolOption::class, Mockery::any())->andReturnUsing(function ($class, $args) { + return new PoolOption(...array_values($args)); + }); + $container->shouldReceive('make')->with(Channel::class, Mockery::any())->andReturnUsing(function ($class, $args) { + return new Channel($args['size']); + }); + + ApplicationContext::setContainer($container); + return new RedisPoolStub($container, 'default'); } } From accfcaccac7d5bcc88a6b4bce7a70ce2b114d1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 18:45:42 +0800 Subject: [PATCH 083/225] Update --- CHANGELOG.md | 4 ++++ phpunit.xml | 1 + 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b8ce7444..8224259c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. - [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd +## Changed + +- [#440](https://github.com/hyperf-cloud/hyperf/pull/440) Automatically close the spare redis client when it is used in low frequency. + ## Deleted - [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Deleted class `Hyperf\JsonRpc\HttpServerFactory`, `Hyperf\HttpServer\ServerFactory`, `Hyperf\GrpcServer\ServerFactory`. diff --git a/phpunit.xml b/phpunit.xml index 445a54672..10b50b31a 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -30,6 +30,7 @@ ./src/logger/tests ./src/model-cache/tests ./src/paginator/tests + ./src/pool/tests ./src/redis/tests ./src/rpc/tests ./src/server/tests From 266687512c31063b41e553385a95f2977cedb575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 18:58:18 +0800 Subject: [PATCH 084/225] Fixed testing. --- src/cache/tests/Cases/RedisDriverTest.php | 5 +++++ src/redis/tests/RedisConnectionTest.php | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cache/tests/Cases/RedisDriverTest.php b/src/cache/tests/Cases/RedisDriverTest.php index 7f0c11164..cf19e0cb2 100644 --- a/src/cache/tests/Cases/RedisDriverTest.php +++ b/src/cache/tests/Cases/RedisDriverTest.php @@ -19,7 +19,9 @@ use Hyperf\Contract\ConfigInterface; use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\Di\Container; use Hyperf\Pool\Channel; +use Hyperf\Pool\LowFrequencyInterface; use Hyperf\Pool\PoolOption; +use Hyperf\Redis\Frequency; use Hyperf\Redis\Pool\PoolFactory; use Hyperf\Redis\Pool\RedisPool; use Hyperf\Redis\Redis; @@ -138,6 +140,9 @@ class RedisDriverTest extends TestCase return new RedisDriver($container, $args['config']); }); $container->shouldReceive('get')->with(PhpSerializerPacker::class)->andReturn(new PhpSerializerPacker()); + $frequency = Mockery::mock(LowFrequencyInterface::class); + $frequency->shouldReceive('isLowFrequency')->andReturn(true); + $container->shouldReceive('make')->with(Frequency::class, Mockery::any())->andReturn($frequency); $container->shouldReceive('make')->with(RedisPool::class, Mockery::any())->andReturnUsing(function ($class, $args) use ($container) { return new RedisPool($container, $args['name']); }); diff --git a/src/redis/tests/RedisConnectionTest.php b/src/redis/tests/RedisConnectionTest.php index 85f42c90b..7cd18bb89 100644 --- a/src/redis/tests/RedisConnectionTest.php +++ b/src/redis/tests/RedisConnectionTest.php @@ -120,7 +120,6 @@ class RedisConnectionTest extends TestCase $frequency = Mockery::mock(LowFrequencyInterface::class); $frequency->shouldReceive('isLowFrequency')->andReturn(true); - $container->shouldReceive('make')->with(Frequency::class, Mockery::any())->andReturn($frequency); $container->shouldReceive('make')->with(PoolOption::class, Mockery::any())->andReturnUsing(function ($class, $args) { return new PoolOption(...array_values($args)); From 8ea8fa031775130c668c5c289bcf03b6b46d5efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 19:03:18 +0800 Subject: [PATCH 085/225] Update composer.json --- src/redis/composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/redis/composer.json b/src/redis/composer.json index b11f3d6d7..02ba71bcd 100644 --- a/src/redis/composer.json +++ b/src/redis/composer.json @@ -12,10 +12,10 @@ }, "require": { "php": ">=7.2", - "psr/container": "^1.0", "hyperf/contract": "~1.1.0", "hyperf/pool": "~1.1.0", - "hyperf/utils": "~1.1.0" + "hyperf/utils": "~1.1.0", + "psr/container": "^1.0" }, "require-dev": { "hyperf/di": "~1.1.0", From 6ca2cdc83faa6ba1001f27a295360890520d1a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 22 Aug 2019 19:06:29 +0800 Subject: [PATCH 086/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8224259c7..b1221d308 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ ## Changed -- [#440](https://github.com/hyperf-cloud/hyperf/pull/440) Automatically close the spare redis client when it is used in low frequency. +- [#441](https://github.com/hyperf-cloud/hyperf/pull/441) Automatically close the spare redis client when it is used in low frequency. ## Deleted From d77246deff22af4403de3510d84ef8956efa1bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 11:01:08 +0800 Subject: [PATCH 087/225] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89610c335..171afa035 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Optimized server and Fixed middleware that user defined does not works. - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. - [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd +- [#420](https://github.com/hyperf-cloud/hyperf/pull/420) Added observer for model. ## Changed From a9e3aca4d97dc2b49b992e71ef7ea37f35dbd673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 11:38:42 +0800 Subject: [PATCH 088/225] Moved testing. --- composer.json | 3 + src/database/src/Model/Concerns/HasEvents.php | 64 ---------------- src/database/src/Model/Events/Event.php | 11 --- src/database/tests/ModelTest.php | 69 ----------------- .../src/Collector/ObserverCollector.php | 7 ++ .../tests/ModelObserverTest.php | 74 +++++++++++++++++++ .../tests/ObserverCollectorTest.php | 56 ++++++++++++++ .../tests/Stub/ModelObserverStub.php | 23 ++++++ src/model-observer/tests/Stub/ModelStub.php | 20 +++++ 9 files changed, 183 insertions(+), 144 deletions(-) create mode 100644 src/model-observer/tests/ModelObserverTest.php create mode 100644 src/model-observer/tests/ObserverCollectorTest.php create mode 100644 src/model-observer/tests/Stub/ModelObserverStub.php create mode 100644 src/model-observer/tests/Stub/ModelStub.php diff --git a/composer.json b/composer.json index 4135c5b63..93ce1cf29 100644 --- a/composer.json +++ b/composer.json @@ -141,6 +141,7 @@ "Hyperf\\Logger\\": "src/logger/src/", "Hyperf\\Memory\\": "src/memory/src/", "Hyperf\\ModelCache\\": "src/model-cache/src/", + "Hyperf\\ModelObserver\\": "src/model-observer/src/", "Hyperf\\Paginator\\": "src/paginator/src/", "Hyperf\\Pool\\": "src/pool/src/", "Hyperf\\Process\\": "src/process/src/", @@ -192,6 +193,7 @@ "HyperfTest\\LoadBalancer\\": "src/load-balancer/tests/", "HyperfTest\\Logger\\": "src/logger/tests/", "HyperfTest\\ModelCache\\": "src/model-cache/tests/", + "HyperfTest\\ModelObserver\\": "src/model-observer/tests/", "HyperfTest\\Paginator\\": "src/paginator/tests/", "HyperfTest\\Pool\\": "src/pool/tests/", "HyperfTest\\Process\\": "src/process/tests/", @@ -240,6 +242,7 @@ "Hyperf\\Logger\\ConfigProvider", "Hyperf\\Memory\\ConfigProvider", "Hyperf\\ModelCache\\ConfigProvider", + "Hyperf\\ModelObserver\\ConfigProvider", "Hyperf\\Paginator\\ConfigProvider", "Hyperf\\Pool\\ConfigProvider", "Hyperf\\Process\\ConfigProvider", diff --git a/src/database/src/Model/Concerns/HasEvents.php b/src/database/src/Model/Concerns/HasEvents.php index 15c712089..53238c4d9 100644 --- a/src/database/src/Model/Concerns/HasEvents.php +++ b/src/database/src/Model/Concerns/HasEvents.php @@ -53,15 +53,6 @@ trait HasEvents */ protected $events = []; - /** - * User exposed observable events. - * - * These are extra user-defined events observers may subscribe to. - * - * @var array - */ - protected static $observables = []; - /** * Register observers with the model. * @@ -77,38 +68,6 @@ trait HasEvents } } - /** - * Clear all registered observers with the model. - * - * @return void - */ - public static function clearObservables(): void - { - static::$observables = []; - } - - /** - * Register a single observer with the model. - * - * @param object|string $class - * @return void - */ - protected function registerObserver($class): void - { - $className = is_string($class) ? $class : get_class($class); - - foreach ($this->getDefaultEvents() as $alias => $eventClass) { - if (method_exists($class, $alias)) { - static::$observables[static::class][$alias] = array_unique( - array_merge( - static::$observables[static::class][$alias] ?? [], - [$className] - ) - ); - } - } - } - /** * Set the user-defined event names. * @@ -168,29 +127,6 @@ trait HasEvents return array_replace($this->getDefaultEvents(), $this->events); } - /** - * Set observable mappings. - * - * @param array $observables - * @return self - */ - public function setObservables(array $observables): self - { - static::$observables[static::class] = $observables; - - return $this; - } - - /** - * Get observable mappings. - * - * @return array - */ - public function getObservables(): array - { - return static::$observables[static::class] ?? []; - } - /** * Get the default events of Hyperf Database Model. * diff --git a/src/database/src/Model/Events/Event.php b/src/database/src/Model/Events/Event.php index 304556134..a7c766ee1 100644 --- a/src/database/src/Model/Events/Event.php +++ b/src/database/src/Model/Events/Event.php @@ -45,12 +45,6 @@ abstract class Event implements StoppableEventInterface $this->getModel()->{$this->getMethod()}($this); } - if ($observerClasses = $this->getObserverClasses()) { - foreach ($observerClasses as $observerClass) { - make($observerClass)->{$this->getMethod()}($this); - } - } - return $this; } @@ -63,9 +57,4 @@ abstract class Event implements StoppableEventInterface { return $this->model; } - - public function getObserverClasses(): array - { - return $this->getModel()->getObservables()[$this->getMethod()] ?? []; - } } diff --git a/src/database/tests/ModelTest.php b/src/database/tests/ModelTest.php index b1405fea7..c56d0c3a1 100644 --- a/src/database/tests/ModelTest.php +++ b/src/database/tests/ModelTest.php @@ -1843,75 +1843,6 @@ class ModelTest extends TestCase $this->assertTrue($called); } - public function testSetObservables() - { - $model = new ModelStub(['id' => 1]); - $model->setObservables($observables = [ - 'created' => ['ObserverClass'] - ]); - - $this->assertSame($observables, $model->getObservables()); - } - - public function testObserve() - { - ModelStub::observe(ModelObserverStub::class); - - $model = new ModelStub(['id' => 1]); - - $this->assertSame(['updating' => [ModelObserverStub::class]], $model->getObservables()); - } - - public function testClearObservables() - { - $model = new ModelStub(['id' => 1]); - $model->setObservables($observables = [ - 'created' => ['ObserverClass'] - ]); - - ModelStub::clearObservables(); - - $this->assertSame([], $model->getObservables()); - } - - public function testGetObserverClassesFromModelEvent() - { - $model = new ModelStub(['id' => 1]); - $model->setObservables($observables = [ - 'updating' => ['ObserverClass'] - ]); - - $saving = new Events\Saving($model, 'saving'); - $updating = new Events\Updating($model, 'updating'); - - $this->assertSame([], $saving->getObserverClasses()); - $this->assertSame(['ObserverClass'], $updating->getObserverClasses()); - } - - public function testHandleModelObserver() - { - $listenerProvider = new ListenerProvider; - $listenerProvider->on(Event::class, [new ModelEventListenerStub, 'process']); - - Register::setEventDispatcher(new EventDispatcher($listenerProvider)); - - $model = $this->getMockBuilder(ModelStub::class)->setMethods(['newModelQuery', 'updateTimestamps'])->getMock(); - $query = Mockery::mock(Builder::class); - $query->shouldReceive('where')->once()->with('id', '=', 1); - $query->shouldReceive('update')->once()->with(['foo' => 'bar'])->andReturn(1); - $model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query)); - $model->expects($this->once())->method('updateTimestamps'); - - $model::observe(ModelObserverStub::class); - - $model->id = 1; - $model->syncOriginal(); - $model->foo = 'foo'; - $model->exists = true; - - $this->assertTrue($model->save()); - } - public function testModelGenerate() { $this->getContainer(); diff --git a/src/model-observer/src/Collector/ObserverCollector.php b/src/model-observer/src/Collector/ObserverCollector.php index c2a8c1889..80067e01c 100644 --- a/src/model-observer/src/Collector/ObserverCollector.php +++ b/src/model-observer/src/Collector/ObserverCollector.php @@ -14,6 +14,13 @@ namespace Hyperf\ModelObserver\Collector; class ObserverCollector { + /** + * User exposed observable events. + * + * These are extra user-defined events observers may subscribe to. + * + * @var array + */ protected static $observables = []; /** diff --git a/src/model-observer/tests/ModelObserverTest.php b/src/model-observer/tests/ModelObserverTest.php new file mode 100644 index 000000000..171c28e1b --- /dev/null +++ b/src/model-observer/tests/ModelObserverTest.php @@ -0,0 +1,74 @@ +getContainer(); + $listenerProvider = new ListenerProvider(); + $listenerProvider->on(Event::class, [new ModelEventListener($container), 'process']); + + Register::setEventDispatcher(new EventDispatcher($listenerProvider)); + + $model = $this->getMockBuilder(ModelStub::class)->setMethods(['newModelQuery', 'updateTimestamps'])->getMock(); + $query = Mockery::mock(Builder::class); + $query->shouldReceive('where')->once()->with('id', '=', 1); + $query->shouldReceive('update')->once()->with(['foo' => 'bar'])->andReturn(1); + $model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query)); + $model->expects($this->once())->method('updateTimestamps'); + + ObserverCollector::register(get_class($model), ModelObserverStub::class); + + $model->id = 1; + $model->syncOriginal(); + $model->foo = 'foo'; + $model->exists = true; + + $this->assertTrue($model->save()); + } + + protected function getContainer() + { + $container = Mockery::mock(ContainerInterface::class); + $container->shouldReceive('has')->andReturn(true); + $container->shouldReceive('get')->with(ModelObserverStub::class)->andReturn(new ModelObserverStub()); + + return $container; + } +} diff --git a/src/model-observer/tests/ObserverCollectorTest.php b/src/model-observer/tests/ObserverCollectorTest.php new file mode 100644 index 000000000..177d646f7 --- /dev/null +++ b/src/model-observer/tests/ObserverCollectorTest.php @@ -0,0 +1,56 @@ +assertSame(['ObserverClass'], ObserverCollector::getObservables($class)); + } + + public function testRegisterMoreThanOneObserver() + { + $class = 'HyperfTest\ModelObserver\Stub\ModelStub'; + ObserverCollector::register($class, 'ObserverClass'); + ObserverCollector::register($class, 'ObserverClass2'); + ObserverCollector::register($class, 'ObserverClass3'); + $this->assertSame(['ObserverClass', 'ObserverClass2', 'ObserverClass3'], ObserverCollector::getObservables($class)); + } + + public function testClearObservables() + { + $class = 'HyperfTest\ModelObserver\Stub\ModelStub'; + ObserverCollector::register($class, 'ObserverClass'); + + ObserverCollector::clearObservables(); + + $this->assertSame([], ObserverCollector::getObservables($class)); + } +} diff --git a/src/model-observer/tests/Stub/ModelObserverStub.php b/src/model-observer/tests/Stub/ModelObserverStub.php new file mode 100644 index 000000000..f17c8077e --- /dev/null +++ b/src/model-observer/tests/Stub/ModelObserverStub.php @@ -0,0 +1,23 @@ +getModel()->foo = 'bar'; + } +} diff --git a/src/model-observer/tests/Stub/ModelStub.php b/src/model-observer/tests/Stub/ModelStub.php new file mode 100644 index 000000000..dd0cf5e07 --- /dev/null +++ b/src/model-observer/tests/Stub/ModelStub.php @@ -0,0 +1,20 @@ + Date: Fri, 23 Aug 2019 11:39:25 +0800 Subject: [PATCH 089/225] Format code. --- src/database/src/Model/Concerns/HasEvents.php | 23 +++-- src/database/src/Model/Events/Event.php | 8 +- src/database/tests/ModelTest.php | 83 +++++++++---------- 3 files changed, 53 insertions(+), 61 deletions(-) diff --git a/src/database/src/Model/Concerns/HasEvents.php b/src/database/src/Model/Concerns/HasEvents.php index 53238c4d9..cfb4d64d7 100644 --- a/src/database/src/Model/Concerns/HasEvents.php +++ b/src/database/src/Model/Concerns/HasEvents.php @@ -12,23 +12,23 @@ declare(strict_types=1); namespace Hyperf\Database\Model\Concerns; -use Hyperf\Utils\Arr; -use Hyperf\Database\Model\Events\Saved; use Hyperf\Database\Model\Events\Booted; -use Hyperf\Database\Model\Events\Saving; use Hyperf\Database\Model\Events\Booting; use Hyperf\Database\Model\Events\Created; -use Hyperf\Database\Model\Events\Deleted; -use Hyperf\Database\Model\Events\Updated; use Hyperf\Database\Model\Events\Creating; +use Hyperf\Database\Model\Events\Deleted; use Hyperf\Database\Model\Events\Deleting; +use Hyperf\Database\Model\Events\ForceDeleted; use Hyperf\Database\Model\Events\Restored; -use Hyperf\Database\Model\Events\Updating; use Hyperf\Database\Model\Events\Restoring; use Hyperf\Database\Model\Events\Retrieved; -use Hyperf\Database\Model\Events\ForceDeleted; -use Psr\EventDispatcher\StoppableEventInterface; +use Hyperf\Database\Model\Events\Saved; +use Hyperf\Database\Model\Events\Saving; +use Hyperf\Database\Model\Events\Updated; +use Hyperf\Database\Model\Events\Updating; +use Hyperf\Utils\Arr; use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\EventDispatcher\StoppableEventInterface; /** * @method retrieved(Retrieved $event) @@ -56,12 +56,11 @@ trait HasEvents /** * Register observers with the model. * - * @param object|array|string $classes - * @return void + * @param array|object|string $classes */ public static function observe($classes): void { - $instance = new static; + $instance = new static(); foreach (Arr::wrap($classes) as $class) { $instance->registerObserver($class); @@ -91,7 +90,6 @@ trait HasEvents * Add some observable event. * * @param array|string $events - * @return void */ public function addEvents($events): void { @@ -102,7 +100,6 @@ trait HasEvents * Remove some registed event. * * @param array $events - * @return void */ public function removeEvents(array $events): void { diff --git a/src/database/src/Model/Events/Event.php b/src/database/src/Model/Events/Event.php index a7c766ee1..75dcb25af 100644 --- a/src/database/src/Model/Events/Event.php +++ b/src/database/src/Model/Events/Event.php @@ -12,12 +12,12 @@ declare(strict_types=1); namespace Hyperf\Database\Model\Events; -use function lcfirst; -use Hyperf\Event\Stoppable; -use function method_exists; -use function class_basename; use Hyperf\Database\Model\Model; +use Hyperf\Event\Stoppable; use Psr\EventDispatcher\StoppableEventInterface; +use function class_basename; +use function lcfirst; +use function method_exists; abstract class Event implements StoppableEventInterface { diff --git a/src/database/tests/ModelTest.php b/src/database/tests/ModelTest.php index c56d0c3a1..1882c2c07 100644 --- a/src/database/tests/ModelTest.php +++ b/src/database/tests/ModelTest.php @@ -12,65 +12,60 @@ declare(strict_types=1); namespace HyperfTest\Database; -use Mockery; -use DateTime; -use stdClass; -use Exception; use Carbon\Carbon; -use ReflectionClass; +use DateTime; use DateTimeImmutable; use DateTimeInterface; -use Hyperf\Utils\Context; -use PHPUnit\Framework\TestCase; -use Hyperf\Database\Model\Model; -use Hyperf\Database\Model\Booted; -use Hyperf\Database\Model\Events; -use Hyperf\Event\EventDispatcher; -use Hyperf\Database\Model\Builder; -use Hyperf\Event\ListenerProvider; -use HyperfTest\Database\Stubs\User; -use Hyperf\Database\Model\Register; -use Hyperf\Utils\InteractsWithTime; -use Hyperf\Utils\ApplicationContext; -use Hyperf\Database\Model\Collection; -use Psr\Container\ContainerInterface; -use Hyperf\Database\ConnectionResolver; -use Hyperf\Database\Model\Events\Event; -use HyperfTest\Database\Stubs\ModelStub; +use Exception; use Hyperf\Database\ConnectionInterface; -use Hyperf\Database\Query\Grammars\Grammar; -use HyperfTest\Database\Stubs\DateModelStub; -use HyperfTest\Database\Stubs\ModelSaveStub; -use HyperfTest\Database\Stubs\ModelWithStub; -use HyperfTest\Database\Stubs\ModelCamelStub; -use Hyperf\Database\Model\Relations\Relation; +use Hyperf\Database\ConnectionInterface as Connection; +use Hyperf\Database\ConnectionResolver; +use Hyperf\Database\ConnectionResolverInterface; +use Hyperf\Database\Connectors\ConnectionFactory; use Hyperf\Database\Connectors\MySqlConnector; +use Hyperf\Database\Model\Booted; +use Hyperf\Database\Model\Builder; +use Hyperf\Database\Model\Collection; +use Hyperf\Database\Model\Events; +use Hyperf\Database\Model\Model; +use Hyperf\Database\Model\Register; use Hyperf\Database\Model\Relations\BelongsTo; +use Hyperf\Database\Model\Relations\Relation; +use Hyperf\Database\Query\Grammars\Grammar; +use Hyperf\Database\Query\Processors\Processor; +use Hyperf\Utils\ApplicationContext; use Hyperf\Utils\Collection as BaseCollection; +use Hyperf\Utils\Context; +use Hyperf\Utils\InteractsWithTime; +use HyperfTest\Database\Stubs\DateModelStub; +use HyperfTest\Database\Stubs\DifferentConnectionModelStub; use HyperfTest\Database\Stubs\KeyTypeModelStub; use HyperfTest\Database\Stubs\ModelAppendsStub; +use HyperfTest\Database\Stubs\ModelBootingTestStub; +use HyperfTest\Database\Stubs\ModelCamelStub; use HyperfTest\Database\Stubs\ModelCastingStub; use HyperfTest\Database\Stubs\ModelDestroyStub; -use Hyperf\Database\Query\Processors\Processor; -use HyperfTest\Database\Stubs\ModelObserverStub; -use Hyperf\Database\ConnectionResolverInterface; -use HyperfTest\Database\Stubs\ModelStubWithTrait; -use Hyperf\Database\Connectors\ConnectionFactory; -use HyperfTest\Database\Stubs\ModelBootingTestStub; -use HyperfTest\Database\Stubs\ModelEventObjectStub; -use HyperfTest\Database\Stubs\ModelGetMutatorsStub; -use HyperfTest\Database\Stubs\ModelSavingEventStub; -use HyperfTest\Database\Stubs\ModelWithoutTableStub; -use HyperfTest\Database\Stubs\NoConnectionModelStub; use HyperfTest\Database\Stubs\ModelDynamicHiddenStub; -use HyperfTest\Database\Stubs\ModelEventListenerStub; use HyperfTest\Database\Stubs\ModelDynamicVisibleStub; -use Hyperf\Database\ConnectionInterface as Connection; -use HyperfTest\Database\Stubs\ModelNonIncrementingStub; -use HyperfTest\Database\Stubs\ModelWithoutRelationStub; +use HyperfTest\Database\Stubs\ModelEventObjectStub; use HyperfTest\Database\Stubs\ModelFindWithWritePdoStub; -use HyperfTest\Database\Stubs\DifferentConnectionModelStub; +use HyperfTest\Database\Stubs\ModelGetMutatorsStub; +use HyperfTest\Database\Stubs\ModelNonIncrementingStub; +use HyperfTest\Database\Stubs\ModelSaveStub; +use HyperfTest\Database\Stubs\ModelSavingEventStub; +use HyperfTest\Database\Stubs\ModelStub; +use HyperfTest\Database\Stubs\ModelStubWithTrait; +use HyperfTest\Database\Stubs\ModelWithoutRelationStub; +use HyperfTest\Database\Stubs\ModelWithoutTableStub; +use HyperfTest\Database\Stubs\ModelWithStub; +use HyperfTest\Database\Stubs\NoConnectionModelStub; +use HyperfTest\Database\Stubs\User; +use Mockery; +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; use Psr\EventDispatcher\EventDispatcherInterface as Dispatcher; +use ReflectionClass; +use stdClass; /** * @internal From 830f13c0d84958d058429f6ab482abeb94a5e02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 11:41:44 +0800 Subject: [PATCH 090/225] Deleted useless code. --- src/database/src/Model/Concerns/HasEvents.php | 15 --------------- src/database/tests/ModelTest.php | 2 -- 2 files changed, 17 deletions(-) diff --git a/src/database/src/Model/Concerns/HasEvents.php b/src/database/src/Model/Concerns/HasEvents.php index cfb4d64d7..2465a6d6a 100644 --- a/src/database/src/Model/Concerns/HasEvents.php +++ b/src/database/src/Model/Concerns/HasEvents.php @@ -26,7 +26,6 @@ use Hyperf\Database\Model\Events\Saved; use Hyperf\Database\Model\Events\Saving; use Hyperf\Database\Model\Events\Updated; use Hyperf\Database\Model\Events\Updating; -use Hyperf\Utils\Arr; use Psr\EventDispatcher\EventDispatcherInterface; use Psr\EventDispatcher\StoppableEventInterface; @@ -53,20 +52,6 @@ trait HasEvents */ protected $events = []; - /** - * Register observers with the model. - * - * @param array|object|string $classes - */ - public static function observe($classes): void - { - $instance = new static(); - - foreach (Arr::wrap($classes) as $class) { - $instance->registerObserver($class); - } - } - /** * Set the user-defined event names. * diff --git a/src/database/tests/ModelTest.php b/src/database/tests/ModelTest.php index 1882c2c07..4c63d666f 100644 --- a/src/database/tests/ModelTest.php +++ b/src/database/tests/ModelTest.php @@ -93,8 +93,6 @@ class ModelTest extends TestCase Carbon::resetToStringFormat(); Booted::$container = []; - - Model::clearObservables(); } public function testAttributeManipulation() From baabc973ea1836793468ec8b74ed442171bbb7de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 11:43:33 +0800 Subject: [PATCH 091/225] Update HasEvents.php --- src/database/src/Model/Concerns/HasEvents.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/database/src/Model/Concerns/HasEvents.php b/src/database/src/Model/Concerns/HasEvents.php index 2465a6d6a..b7aa4a233 100644 --- a/src/database/src/Model/Concerns/HasEvents.php +++ b/src/database/src/Model/Concerns/HasEvents.php @@ -54,8 +54,6 @@ trait HasEvents /** * Set the user-defined event names. - * - * @return self */ public function setEvents(array $events): self { @@ -83,8 +81,6 @@ trait HasEvents /** * Remove some registed event. - * - * @param array $events */ public function removeEvents(array $events): void { @@ -111,8 +107,6 @@ trait HasEvents /** * Get the default events of Hyperf Database Model. - * - * @return array */ protected function getDefaultEvents(): array { From 06ef33dc3c496f24a01628ca6b6e23d284ae5f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 14:42:05 +0800 Subject: [PATCH 092/225] Renamed model-listener from model-observer. --- composer.json | 6 +++--- src/db-connection/composer.json | 1 + .../.gitattributes | 0 .../LICENSE.md | 0 .../composer.json | 12 ++++++------ .../src/Annotation/Observer.php | 4 ++-- .../src/Collector/ObserverCollector.php | 2 +- .../src/ConfigProvider.php | 2 +- .../src/Listener/ModelEventListener.php | 4 ++-- .../src/Listener/ModelHookEventListener.php} | 4 ++-- .../tests/ModelObserverTest.php | 18 +++++++++--------- .../tests/ObserverCollectorTest.php | 10 +++++----- .../tests/Stub/ModelListenerStub.php} | 4 ++-- .../tests/Stub/ModelStub.php | 2 +- 14 files changed, 35 insertions(+), 34 deletions(-) rename src/{model-observer => model-listener}/.gitattributes (100%) rename src/{model-observer => model-listener}/LICENSE.md (100%) rename src/{model-observer => model-listener}/composer.json (79%) rename src/{model-observer => model-listener}/src/Annotation/Observer.php (87%) rename src/{model-observer => model-listener}/src/Collector/ObserverCollector.php (96%) rename src/{model-observer => model-listener}/src/ConfigProvider.php (94%) rename src/{model-observer => model-listener}/src/Listener/ModelEventListener.php (93%) rename src/{db-connection/src/Listener/ModelEventListener.php => model-listener/src/Listener/ModelHookEventListener.php} (88%) rename src/{model-observer => model-listener}/tests/ModelObserverTest.php (77%) rename src/{model-observer => model-listener}/tests/ObserverCollectorTest.php (83%) rename src/{model-observer/tests/Stub/ModelObserverStub.php => model-listener/tests/Stub/ModelListenerStub.php} (85%) rename src/{model-observer => model-listener}/tests/Stub/ModelStub.php (89%) diff --git a/composer.json b/composer.json index 93ce1cf29..76a1de1b5 100644 --- a/composer.json +++ b/composer.json @@ -141,7 +141,7 @@ "Hyperf\\Logger\\": "src/logger/src/", "Hyperf\\Memory\\": "src/memory/src/", "Hyperf\\ModelCache\\": "src/model-cache/src/", - "Hyperf\\ModelObserver\\": "src/model-observer/src/", + "Hyperf\\ModelListener\\": "src/model-listener/src/", "Hyperf\\Paginator\\": "src/paginator/src/", "Hyperf\\Pool\\": "src/pool/src/", "Hyperf\\Process\\": "src/process/src/", @@ -193,7 +193,7 @@ "HyperfTest\\LoadBalancer\\": "src/load-balancer/tests/", "HyperfTest\\Logger\\": "src/logger/tests/", "HyperfTest\\ModelCache\\": "src/model-cache/tests/", - "HyperfTest\\ModelObserver\\": "src/model-observer/tests/", + "HyperfTest\\ModelListener\\": "src/model-listener/tests/", "HyperfTest\\Paginator\\": "src/paginator/tests/", "HyperfTest\\Pool\\": "src/pool/tests/", "HyperfTest\\Process\\": "src/process/tests/", @@ -242,7 +242,7 @@ "Hyperf\\Logger\\ConfigProvider", "Hyperf\\Memory\\ConfigProvider", "Hyperf\\ModelCache\\ConfigProvider", - "Hyperf\\ModelObserver\\ConfigProvider", + "Hyperf\\ModelListener\\ConfigProvider", "Hyperf\\Paginator\\ConfigProvider", "Hyperf\\Pool\\ConfigProvider", "Hyperf\\Process\\ConfigProvider", diff --git a/src/db-connection/composer.json b/src/db-connection/composer.json index 1c8a7feb3..055e63405 100644 --- a/src/db-connection/composer.json +++ b/src/db-connection/composer.json @@ -16,6 +16,7 @@ "hyperf/database": "~1.1.0", "hyperf/di": "~1.1.0", "hyperf/event": "~1.1.0", + "hyperf/model-listener": "~1.1.0", "hyperf/pool": "~1.1.0", "hyperf/utils": "~1.1.0" }, diff --git a/src/model-observer/.gitattributes b/src/model-listener/.gitattributes similarity index 100% rename from src/model-observer/.gitattributes rename to src/model-listener/.gitattributes diff --git a/src/model-observer/LICENSE.md b/src/model-listener/LICENSE.md similarity index 100% rename from src/model-observer/LICENSE.md rename to src/model-listener/LICENSE.md diff --git a/src/model-observer/composer.json b/src/model-listener/composer.json similarity index 79% rename from src/model-observer/composer.json rename to src/model-listener/composer.json index f2256b20c..f677e535d 100644 --- a/src/model-observer/composer.json +++ b/src/model-listener/composer.json @@ -1,12 +1,12 @@ { - "name": "hyperf/model-observer", - "description": "A model observer for Hyperf.", + "name": "hyperf/model-listener", + "description": "A model listener for Hyperf.", "license": "MIT", "keywords": [ "php", "swoole", "hyperf", - "model-observer" + "model-listener" ], "support": { }, @@ -30,12 +30,12 @@ }, "autoload": { "psr-4": { - "Hyperf\\ModelObserver\\": "src/" + "Hyperf\\ModelListener\\": "src/" } }, "autoload-dev": { "psr-4": { - "HyperfTest\\ModelObserver\\": "tests/" + "HyperfTest\\ModelListener\\": "tests/" } }, "config": { @@ -46,7 +46,7 @@ "dev-master": "1.1-dev" }, "hyperf": { - "config": "Hyperf\\ModelObserver\\ConfigProvider" + "config": "Hyperf\\ModelListener\\ConfigProvider" } }, "bin": [ diff --git a/src/model-observer/src/Annotation/Observer.php b/src/model-listener/src/Annotation/Observer.php similarity index 87% rename from src/model-observer/src/Annotation/Observer.php rename to src/model-listener/src/Annotation/Observer.php index 0660d6233..d31c29f20 100644 --- a/src/model-observer/src/Annotation/Observer.php +++ b/src/model-listener/src/Annotation/Observer.php @@ -10,10 +10,10 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\ModelObserver; +namespace Hyperf\ModelListener; use Hyperf\Di\Annotation\AbstractAnnotation; -use Hyperf\ModelObserver\Collector\ObserverCollector; +use Hyperf\ModelListener\Collector\ObserverCollector; /** * @Annotation diff --git a/src/model-observer/src/Collector/ObserverCollector.php b/src/model-listener/src/Collector/ObserverCollector.php similarity index 96% rename from src/model-observer/src/Collector/ObserverCollector.php rename to src/model-listener/src/Collector/ObserverCollector.php index 80067e01c..6e9b83306 100644 --- a/src/model-observer/src/Collector/ObserverCollector.php +++ b/src/model-listener/src/Collector/ObserverCollector.php @@ -10,7 +10,7 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\ModelObserver\Collector; +namespace Hyperf\ModelListener\Collector; class ObserverCollector { diff --git a/src/model-observer/src/ConfigProvider.php b/src/model-listener/src/ConfigProvider.php similarity index 94% rename from src/model-observer/src/ConfigProvider.php rename to src/model-listener/src/ConfigProvider.php index d86820e83..91c08c8c8 100644 --- a/src/model-observer/src/ConfigProvider.php +++ b/src/model-listener/src/ConfigProvider.php @@ -10,7 +10,7 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\ModelObserver; +namespace Hyperf\ModelListener; class ConfigProvider { diff --git a/src/model-observer/src/Listener/ModelEventListener.php b/src/model-listener/src/Listener/ModelEventListener.php similarity index 93% rename from src/model-observer/src/Listener/ModelEventListener.php rename to src/model-listener/src/Listener/ModelEventListener.php index 343bd988d..a139ade67 100644 --- a/src/model-observer/src/Listener/ModelEventListener.php +++ b/src/model-listener/src/Listener/ModelEventListener.php @@ -10,12 +10,12 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\ModelObserver\Listener; +namespace Hyperf\ModelListener\Listener; use Hyperf\Database\Model\Events\Event; use Hyperf\Event\Annotation\Listener; use Hyperf\Event\Contract\ListenerInterface; -use Hyperf\ModelObserver\Collector\ObserverCollector; +use Hyperf\ModelListener\Collector\ObserverCollector; use Psr\Container\ContainerInterface; /** diff --git a/src/db-connection/src/Listener/ModelEventListener.php b/src/model-listener/src/Listener/ModelHookEventListener.php similarity index 88% rename from src/db-connection/src/Listener/ModelEventListener.php rename to src/model-listener/src/Listener/ModelHookEventListener.php index 08426466d..e6052e504 100644 --- a/src/db-connection/src/Listener/ModelEventListener.php +++ b/src/model-listener/src/Listener/ModelHookEventListener.php @@ -17,9 +17,9 @@ use Hyperf\Event\Annotation\Listener; use Hyperf\Event\Contract\ListenerInterface; /** - * @Listener + * @Listener(priority=99) */ -class ModelEventListener implements ListenerInterface +class ModelHookEventListener implements ListenerInterface { public function listen(): array { diff --git a/src/model-observer/tests/ModelObserverTest.php b/src/model-listener/tests/ModelObserverTest.php similarity index 77% rename from src/model-observer/tests/ModelObserverTest.php rename to src/model-listener/tests/ModelObserverTest.php index 171c28e1b..b71913c09 100644 --- a/src/model-observer/tests/ModelObserverTest.php +++ b/src/model-listener/tests/ModelObserverTest.php @@ -10,17 +10,17 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace HyperfTest\ModelObserver; +namespace HyperfTest\ModelListener; use Hyperf\Database\Model\Builder; use Hyperf\Database\Model\Events\Event; use Hyperf\Database\Model\Register; use Hyperf\Event\EventDispatcher; use Hyperf\Event\ListenerProvider; -use Hyperf\ModelObserver\Collector\ObserverCollector; -use Hyperf\ModelObserver\Listener\ModelEventListener; -use HyperfTest\ModelObserver\Stub\ModelObserverStub; -use HyperfTest\ModelObserver\Stub\ModelStub; +use Hyperf\ModelListener\Collector\ObserverCollector; +use Hyperf\ModelListener\Listener\ModelEventListener; +use HyperfTest\ModelListener\Stub\ModelListenerStub; +use HyperfTest\ModelListener\Stub\ModelStub; use Mockery; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; @@ -29,7 +29,7 @@ use Psr\Container\ContainerInterface; * @internal * @coversNothing */ -class ModelObserverTest extends TestCase +class ModelListenerTest extends TestCase { protected function tearDown() { @@ -38,7 +38,7 @@ class ModelObserverTest extends TestCase ObserverCollector::clearObservables(); } - public function testHandleModelObserver() + public function testHandleModelListener() { $container = $this->getContainer(); $listenerProvider = new ListenerProvider(); @@ -53,7 +53,7 @@ class ModelObserverTest extends TestCase $model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query)); $model->expects($this->once())->method('updateTimestamps'); - ObserverCollector::register(get_class($model), ModelObserverStub::class); + ObserverCollector::register(get_class($model), ModelListenerStub::class); $model->id = 1; $model->syncOriginal(); @@ -67,7 +67,7 @@ class ModelObserverTest extends TestCase { $container = Mockery::mock(ContainerInterface::class); $container->shouldReceive('has')->andReturn(true); - $container->shouldReceive('get')->with(ModelObserverStub::class)->andReturn(new ModelObserverStub()); + $container->shouldReceive('get')->with(ModelListenerStub::class)->andReturn(new ModelListenerStub()); return $container; } diff --git a/src/model-observer/tests/ObserverCollectorTest.php b/src/model-listener/tests/ObserverCollectorTest.php similarity index 83% rename from src/model-observer/tests/ObserverCollectorTest.php rename to src/model-listener/tests/ObserverCollectorTest.php index 177d646f7..ce7dfba8b 100644 --- a/src/model-observer/tests/ObserverCollectorTest.php +++ b/src/model-listener/tests/ObserverCollectorTest.php @@ -10,9 +10,9 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace HyperfTest\ModelObserver; +namespace HyperfTest\ModelListener; -use Hyperf\ModelObserver\Collector\ObserverCollector; +use Hyperf\ModelListener\Collector\ObserverCollector; use PHPUnit\Framework\TestCase; /** @@ -30,14 +30,14 @@ class ObserverCollectorTest extends TestCase public function testRegisterObserver() { - $class = 'HyperfTest\ModelObserver\Stub\ModelStub'; + $class = 'HyperfTest\ModelListener\Stub\ModelStub'; ObserverCollector::register($class, 'ObserverClass'); $this->assertSame(['ObserverClass'], ObserverCollector::getObservables($class)); } public function testRegisterMoreThanOneObserver() { - $class = 'HyperfTest\ModelObserver\Stub\ModelStub'; + $class = 'HyperfTest\ModelListener\Stub\ModelStub'; ObserverCollector::register($class, 'ObserverClass'); ObserverCollector::register($class, 'ObserverClass2'); ObserverCollector::register($class, 'ObserverClass3'); @@ -46,7 +46,7 @@ class ObserverCollectorTest extends TestCase public function testClearObservables() { - $class = 'HyperfTest\ModelObserver\Stub\ModelStub'; + $class = 'HyperfTest\ModelListener\Stub\ModelStub'; ObserverCollector::register($class, 'ObserverClass'); ObserverCollector::clearObservables(); diff --git a/src/model-observer/tests/Stub/ModelObserverStub.php b/src/model-listener/tests/Stub/ModelListenerStub.php similarity index 85% rename from src/model-observer/tests/Stub/ModelObserverStub.php rename to src/model-listener/tests/Stub/ModelListenerStub.php index f17c8077e..9fcf83946 100644 --- a/src/model-observer/tests/Stub/ModelObserverStub.php +++ b/src/model-listener/tests/Stub/ModelListenerStub.php @@ -10,11 +10,11 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace HyperfTest\ModelObserver\Stub; +namespace HyperfTest\ModelListener\Stub; use Hyperf\Database\Model\Events\Updating; -class ModelObserverStub +class ModelListenerStub { public function updating(Updating $event) { diff --git a/src/model-observer/tests/Stub/ModelStub.php b/src/model-listener/tests/Stub/ModelStub.php similarity index 89% rename from src/model-observer/tests/Stub/ModelStub.php rename to src/model-listener/tests/Stub/ModelStub.php index dd0cf5e07..eea02b809 100644 --- a/src/model-observer/tests/Stub/ModelStub.php +++ b/src/model-listener/tests/Stub/ModelStub.php @@ -10,7 +10,7 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace HyperfTest\ModelObserver\Stub; +namespace HyperfTest\ModelListener\Stub; use Hyperf\Database\Model\Model; From 3f30806c18af9d8b4000c6930418f6194d8c1f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=9F=8E=E9=93=AD?= <767036228@qq.com> Date: Fri, 23 Aug 2019 14:50:00 +0800 Subject: [PATCH 093/225] Update command.md --- doc/zh/command.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/zh/command.md b/doc/zh/command.md index 235b9673b..c50aaafc3 100644 --- a/doc/zh/command.md +++ b/doc/zh/command.md @@ -130,6 +130,7 @@ namespace App\Command; use Hyperf\Command\Annotation\Command; use Hyperf\Command\Command as HyperfCommand; +use Symfony\Component\Console\Input\InputArgument; /** * @Command From 6aa274632decacc4cf37f9a4714c930440b11bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=9F=8E=E9=93=AD?= <767036228@qq.com> Date: Fri, 23 Aug 2019 14:50:56 +0800 Subject: [PATCH 094/225] Update command.md --- doc/en/command.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/en/command.md b/doc/en/command.md index 10c35cd12..d36da0e78 100644 --- a/doc/en/command.md +++ b/doc/en/command.md @@ -130,6 +130,7 @@ namespace App\Command; use Hyperf\Command\Annotation\Command; use Hyperf\Command\Command as HyperfCommand; +use Symfony\Component\Console\Input\InputArgument; /** * @Command From 73c1f470b894042f8e51ec5e06d2b8a4550d8b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 15:00:43 +0800 Subject: [PATCH 095/225] Support collect models. --- src/db-connection/composer.json | 1 - src/model-listener/composer.json | 2 +- src/model-listener/src/AbstractListener.php | 44 ++++++++++++++ .../src/Annotation/Observer.php | 20 ++++++- src/model-listener/tests/AnnotationTest.php | 60 +++++++++++++++++++ 5 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 src/model-listener/src/AbstractListener.php create mode 100644 src/model-listener/tests/AnnotationTest.php diff --git a/src/db-connection/composer.json b/src/db-connection/composer.json index 055e63405..355755540 100644 --- a/src/db-connection/composer.json +++ b/src/db-connection/composer.json @@ -15,7 +15,6 @@ "hyperf/framework": "~1.1.0", "hyperf/database": "~1.1.0", "hyperf/di": "~1.1.0", - "hyperf/event": "~1.1.0", "hyperf/model-listener": "~1.1.0", "hyperf/pool": "~1.1.0", "hyperf/utils": "~1.1.0" diff --git a/src/model-listener/composer.json b/src/model-listener/composer.json index f677e535d..2b938586d 100644 --- a/src/model-listener/composer.json +++ b/src/model-listener/composer.json @@ -15,9 +15,9 @@ "hyperf/contract": "~1.1.0", "hyperf/database": "~1.1.0", "hyperf/di": "~1.1.0", + "hyperf/event": "~1.1.0", "hyperf/utils": "~1.1.0", "psr/container": "^1.0", - "psr/event-dispatcher": "^1.0", "psr/log": "^1.0" }, "require-dev": { diff --git a/src/model-listener/src/AbstractListener.php b/src/model-listener/src/AbstractListener.php new file mode 100644 index 000000000..40c813a24 --- /dev/null +++ b/src/model-listener/src/AbstractListener.php @@ -0,0 +1,44 @@ +models = [$value]; + } elseif (is_array($value) && ! Arr::isAssoc($value)) { + $this->models = $value; + } else { + parent::__construct($value); + } + } public function collectClass(string $className): void { parent::collectClass($className); - ObserverCollector::set($this->model, $className); + foreach ($this->models as $model) { + ObserverCollector::register($model, $className); + } } } diff --git a/src/model-listener/tests/AnnotationTest.php b/src/model-listener/tests/AnnotationTest.php new file mode 100644 index 000000000..3ed844d60 --- /dev/null +++ b/src/model-listener/tests/AnnotationTest.php @@ -0,0 +1,60 @@ +collectClass('Foo'); + + $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); + + // $annotation = new Observer(['model' => ModelStub::class]); + // $annotation->collectClass('Foo'); + // + // $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); + } + + public function testAnnotationCollectAssocArray() + { + $annotation = new Observer(['models' => [ModelStub::class]]); + $annotation->collectClass('Foo'); + $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); + } + + public function testAnnotationCollectArray() + { + $annotation = new Observer([ModelStub::class, 'ModelStub']); + $annotation->collectClass('Foo'); + $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); + $this->assertSame(['Foo'], ObserverCollector::getObservables('ModelStub')); + } +} From c8f0e2ffeb3311ae2dcbcc118e0f1ee8039f52b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 15:12:11 +0800 Subject: [PATCH 096/225] Update ModelHookEventListener.php --- src/model-listener/src/Listener/ModelHookEventListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model-listener/src/Listener/ModelHookEventListener.php b/src/model-listener/src/Listener/ModelHookEventListener.php index e6052e504..e49ca5caa 100644 --- a/src/model-listener/src/Listener/ModelHookEventListener.php +++ b/src/model-listener/src/Listener/ModelHookEventListener.php @@ -10,7 +10,7 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\DbConnection\Listener; +namespace Hyperf\ModelListener\Listener; use Hyperf\Database\Model\Events\Event; use Hyperf\Event\Annotation\Listener; From f84bc3ff01f159f102aa1dd495cbae1b62257f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 15:23:54 +0800 Subject: [PATCH 097/225] Fixed bug. --- src/model-listener/src/Annotation/Observer.php | 14 ++++++++------ src/model-listener/tests/AnnotationTest.php | 9 ++------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/model-listener/src/Annotation/Observer.php b/src/model-listener/src/Annotation/Observer.php index eddb19dd2..2a02dfa5a 100644 --- a/src/model-listener/src/Annotation/Observer.php +++ b/src/model-listener/src/Annotation/Observer.php @@ -29,12 +29,14 @@ class Observer extends AbstractAnnotation public function __construct($value = null) { - if (is_string($value)) { - $this->models = [$value]; - } elseif (is_array($value) && ! Arr::isAssoc($value)) { - $this->models = $value; - } else { - parent::__construct($value); + parent::__construct($value); + + if ($value = $value['value'] ?? null) { + if (is_string($value)) { + $this->models = [$value]; + } elseif (is_array($value) && ! Arr::isAssoc($value)) { + $this->models = $value; + } } } diff --git a/src/model-listener/tests/AnnotationTest.php b/src/model-listener/tests/AnnotationTest.php index 3ed844d60..7887e0e76 100644 --- a/src/model-listener/tests/AnnotationTest.php +++ b/src/model-listener/tests/AnnotationTest.php @@ -32,15 +32,10 @@ class AnnotationTest extends TestCase public function testAnnotationCollect() { - $annotation = new Observer(ModelStub::class); + $annotation = new Observer(['value' => ModelStub::class]); $annotation->collectClass('Foo'); $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); - - // $annotation = new Observer(['model' => ModelStub::class]); - // $annotation->collectClass('Foo'); - // - // $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); } public function testAnnotationCollectAssocArray() @@ -52,7 +47,7 @@ class AnnotationTest extends TestCase public function testAnnotationCollectArray() { - $annotation = new Observer([ModelStub::class, 'ModelStub']); + $annotation = new Observer(['value' => [ModelStub::class, 'ModelStub']]); $annotation->collectClass('Foo'); $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); $this->assertSame(['Foo'], ObserverCollector::getObservables('ModelStub')); From fa0b3bfc981ae6487687fcd6f029188595b06c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 15:32:16 +0800 Subject: [PATCH 098/225] Renamed ModelListener. --- .../src/Annotation/{Observer.php => ModelListener.php} | 2 +- src/model-listener/tests/AnnotationTest.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/model-listener/src/Annotation/{Observer.php => ModelListener.php} (95%) diff --git a/src/model-listener/src/Annotation/Observer.php b/src/model-listener/src/Annotation/ModelListener.php similarity index 95% rename from src/model-listener/src/Annotation/Observer.php rename to src/model-listener/src/Annotation/ModelListener.php index 2a02dfa5a..a46e114ee 100644 --- a/src/model-listener/src/Annotation/Observer.php +++ b/src/model-listener/src/Annotation/ModelListener.php @@ -20,7 +20,7 @@ use Hyperf\Utils\Arr; * @Annotation * @Target({"CLASS"}) */ -class Observer extends AbstractAnnotation +class ModelListener extends AbstractAnnotation { /** * @var array diff --git a/src/model-listener/tests/AnnotationTest.php b/src/model-listener/tests/AnnotationTest.php index 7887e0e76..deaa1fa79 100644 --- a/src/model-listener/tests/AnnotationTest.php +++ b/src/model-listener/tests/AnnotationTest.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace HyperfTest\ModelListener; use Hyperf\ModelListener\Collector\ObserverCollector; -use Hyperf\ModelListener\Observer; +use Hyperf\ModelListener\ModelListener; use HyperfTest\ModelListener\Stub\ModelStub; use PHPUnit\Framework\TestCase; @@ -32,7 +32,7 @@ class AnnotationTest extends TestCase public function testAnnotationCollect() { - $annotation = new Observer(['value' => ModelStub::class]); + $annotation = new ModelListener(['value' => ModelStub::class]); $annotation->collectClass('Foo'); $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); @@ -40,14 +40,14 @@ class AnnotationTest extends TestCase public function testAnnotationCollectAssocArray() { - $annotation = new Observer(['models' => [ModelStub::class]]); + $annotation = new ModelListener(['models' => [ModelStub::class]]); $annotation->collectClass('Foo'); $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); } public function testAnnotationCollectArray() { - $annotation = new Observer(['value' => [ModelStub::class, 'ModelStub']]); + $annotation = new ModelListener(['value' => [ModelStub::class, 'ModelStub']]); $annotation->collectClass('Foo'); $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); $this->assertSame(['Foo'], ObserverCollector::getObservables('ModelStub')); From 77a93cb1843c9b8602e8c01323fe7875e4db3beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 15:41:07 +0800 Subject: [PATCH 099/225] Renamed ListenerCollector. --- .../src/Annotation/ModelListener.php | 4 ++-- ...verCollector.php => ListenerCollector.php} | 16 +++++++------- .../src/Listener/ModelEventListener.php | 4 ++-- src/model-listener/tests/AnnotationTest.php | 12 +++++----- .../tests/ModelObserverTest.php | 6 ++--- .../tests/ObserverCollectorTest.php | 22 +++++++++---------- 6 files changed, 32 insertions(+), 32 deletions(-) rename src/model-listener/src/Collector/{ObserverCollector.php => ListenerCollector.php} (69%) diff --git a/src/model-listener/src/Annotation/ModelListener.php b/src/model-listener/src/Annotation/ModelListener.php index a46e114ee..8b097f320 100644 --- a/src/model-listener/src/Annotation/ModelListener.php +++ b/src/model-listener/src/Annotation/ModelListener.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace Hyperf\ModelListener; use Hyperf\Di\Annotation\AbstractAnnotation; -use Hyperf\ModelListener\Collector\ObserverCollector; +use Hyperf\ModelListener\Collector\ListenerCollector; use Hyperf\Utils\Arr; /** @@ -45,7 +45,7 @@ class ModelListener extends AbstractAnnotation parent::collectClass($className); foreach ($this->models as $model) { - ObserverCollector::register($model, $className); + ListenerCollector::register($model, $className); } } } diff --git a/src/model-listener/src/Collector/ObserverCollector.php b/src/model-listener/src/Collector/ListenerCollector.php similarity index 69% rename from src/model-listener/src/Collector/ObserverCollector.php rename to src/model-listener/src/Collector/ListenerCollector.php index 6e9b83306..08e3a9192 100644 --- a/src/model-listener/src/Collector/ObserverCollector.php +++ b/src/model-listener/src/Collector/ListenerCollector.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Hyperf\ModelListener\Collector; -class ObserverCollector +class ListenerCollector { /** * User exposed observable events. @@ -21,16 +21,16 @@ class ObserverCollector * * @var array */ - protected static $observables = []; + protected static $listeners = []; /** * Register a single observer with the model. */ public static function register(string $model, string $observer): void { - static::$observables[$model] = array_unique( + static::$listeners[$model] = array_unique( array_merge( - static::$observables[$model] ?? [], + static::$listeners[$model] ?? [], [$observer] ) ); @@ -41,16 +41,16 @@ class ObserverCollector * * @return array */ - public static function getObservables(string $model): array + public static function getListeners(string $model): array { - return static::$observables[$model] ?? []; + return static::$listeners[$model] ?? []; } /** * Clear all registered observers with the model. */ - public static function clearObservables(): void + public static function clearListeners(): void { - static::$observables = []; + static::$listeners = []; } } diff --git a/src/model-listener/src/Listener/ModelEventListener.php b/src/model-listener/src/Listener/ModelEventListener.php index a139ade67..7152060f7 100644 --- a/src/model-listener/src/Listener/ModelEventListener.php +++ b/src/model-listener/src/Listener/ModelEventListener.php @@ -15,7 +15,7 @@ namespace Hyperf\ModelListener\Listener; use Hyperf\Database\Model\Events\Event; use Hyperf\Event\Annotation\Listener; use Hyperf\Event\Contract\ListenerInterface; -use Hyperf\ModelListener\Collector\ObserverCollector; +use Hyperf\ModelListener\Collector\ListenerCollector; use Psr\Container\ContainerInterface; /** @@ -49,7 +49,7 @@ class ModelEventListener implements ListenerInterface $model = $event->getModel(); $modelName = get_class($model); - $observers = ObserverCollector::getObservables($modelName); + $observers = ListenerCollector::getListeners($modelName); foreach ($observers as $name) { if (! $this->container->has($name)) { continue; diff --git a/src/model-listener/tests/AnnotationTest.php b/src/model-listener/tests/AnnotationTest.php index deaa1fa79..72c3b980c 100644 --- a/src/model-listener/tests/AnnotationTest.php +++ b/src/model-listener/tests/AnnotationTest.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace HyperfTest\ModelListener; -use Hyperf\ModelListener\Collector\ObserverCollector; +use Hyperf\ModelListener\Collector\ListenerCollector; use Hyperf\ModelListener\ModelListener; use HyperfTest\ModelListener\Stub\ModelStub; use PHPUnit\Framework\TestCase; @@ -27,7 +27,7 @@ class AnnotationTest extends TestCase { parent::tearDown(); - ObserverCollector::clearObservables(); + ListenerCollector::clearListeners(); } public function testAnnotationCollect() @@ -35,21 +35,21 @@ class AnnotationTest extends TestCase $annotation = new ModelListener(['value' => ModelStub::class]); $annotation->collectClass('Foo'); - $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); + $this->assertSame(['Foo'], ListenerCollector::getListeners(ModelStub::class)); } public function testAnnotationCollectAssocArray() { $annotation = new ModelListener(['models' => [ModelStub::class]]); $annotation->collectClass('Foo'); - $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); + $this->assertSame(['Foo'], ListenerCollector::getListeners(ModelStub::class)); } public function testAnnotationCollectArray() { $annotation = new ModelListener(['value' => [ModelStub::class, 'ModelStub']]); $annotation->collectClass('Foo'); - $this->assertSame(['Foo'], ObserverCollector::getObservables(ModelStub::class)); - $this->assertSame(['Foo'], ObserverCollector::getObservables('ModelStub')); + $this->assertSame(['Foo'], ListenerCollector::getListeners(ModelStub::class)); + $this->assertSame(['Foo'], ListenerCollector::getListeners('ModelStub')); } } diff --git a/src/model-listener/tests/ModelObserverTest.php b/src/model-listener/tests/ModelObserverTest.php index b71913c09..f3c28113e 100644 --- a/src/model-listener/tests/ModelObserverTest.php +++ b/src/model-listener/tests/ModelObserverTest.php @@ -17,7 +17,7 @@ use Hyperf\Database\Model\Events\Event; use Hyperf\Database\Model\Register; use Hyperf\Event\EventDispatcher; use Hyperf\Event\ListenerProvider; -use Hyperf\ModelListener\Collector\ObserverCollector; +use Hyperf\ModelListener\Collector\ListenerCollector; use Hyperf\ModelListener\Listener\ModelEventListener; use HyperfTest\ModelListener\Stub\ModelListenerStub; use HyperfTest\ModelListener\Stub\ModelStub; @@ -35,7 +35,7 @@ class ModelListenerTest extends TestCase { parent::tearDown(); - ObserverCollector::clearObservables(); + ListenerCollector::clearListeners(); } public function testHandleModelListener() @@ -53,7 +53,7 @@ class ModelListenerTest extends TestCase $model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query)); $model->expects($this->once())->method('updateTimestamps'); - ObserverCollector::register(get_class($model), ModelListenerStub::class); + ListenerCollector::register(get_class($model), ModelListenerStub::class); $model->id = 1; $model->syncOriginal(); diff --git a/src/model-listener/tests/ObserverCollectorTest.php b/src/model-listener/tests/ObserverCollectorTest.php index ce7dfba8b..a7e2d5679 100644 --- a/src/model-listener/tests/ObserverCollectorTest.php +++ b/src/model-listener/tests/ObserverCollectorTest.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace HyperfTest\ModelListener; -use Hyperf\ModelListener\Collector\ObserverCollector; +use Hyperf\ModelListener\Collector\ListenerCollector; use PHPUnit\Framework\TestCase; /** @@ -25,32 +25,32 @@ class ObserverCollectorTest extends TestCase { parent::tearDown(); - ObserverCollector::clearObservables(); + ListenerCollector::clearListeners(); } public function testRegisterObserver() { $class = 'HyperfTest\ModelListener\Stub\ModelStub'; - ObserverCollector::register($class, 'ObserverClass'); - $this->assertSame(['ObserverClass'], ObserverCollector::getObservables($class)); + ListenerCollector::register($class, 'ObserverClass'); + $this->assertSame(['ObserverClass'], ListenerCollector::getListeners($class)); } public function testRegisterMoreThanOneObserver() { $class = 'HyperfTest\ModelListener\Stub\ModelStub'; - ObserverCollector::register($class, 'ObserverClass'); - ObserverCollector::register($class, 'ObserverClass2'); - ObserverCollector::register($class, 'ObserverClass3'); - $this->assertSame(['ObserverClass', 'ObserverClass2', 'ObserverClass3'], ObserverCollector::getObservables($class)); + ListenerCollector::register($class, 'ObserverClass'); + ListenerCollector::register($class, 'ObserverClass2'); + ListenerCollector::register($class, 'ObserverClass3'); + $this->assertSame(['ObserverClass', 'ObserverClass2', 'ObserverClass3'], ListenerCollector::getListeners($class)); } public function testClearObservables() { $class = 'HyperfTest\ModelListener\Stub\ModelStub'; - ObserverCollector::register($class, 'ObserverClass'); + ListenerCollector::register($class, 'ObserverClass'); - ObserverCollector::clearObservables(); + ListenerCollector::clearListeners(); - $this->assertSame([], ObserverCollector::getObservables($class)); + $this->assertSame([], ListenerCollector::getListeners($class)); } } From 124468c8017ba6f9aad453aacdbc10b190537ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 15:45:37 +0800 Subject: [PATCH 100/225] Update ListenerCollector.php --- .../src/Collector/ListenerCollector.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/model-listener/src/Collector/ListenerCollector.php b/src/model-listener/src/Collector/ListenerCollector.php index 08e3a9192..7fe6febcd 100644 --- a/src/model-listener/src/Collector/ListenerCollector.php +++ b/src/model-listener/src/Collector/ListenerCollector.php @@ -15,39 +15,39 @@ namespace Hyperf\ModelListener\Collector; class ListenerCollector { /** - * User exposed observable events. + * User exposed listeners. * - * These are extra user-defined events observers may subscribe to. + * These are extra user-defined events listeners may subscribe to. * * @var array */ protected static $listeners = []; /** - * Register a single observer with the model. + * Register a single listener with the model. */ - public static function register(string $model, string $observer): void + public static function register(string $model, string $listener): void { static::$listeners[$model] = array_unique( array_merge( static::$listeners[$model] ?? [], - [$observer] + [$listener] ) ); } - /** - * Get observable mappings. - * - * @return array - */ + public static function setListeners(string $model, array $listeners): void + { + static::$listeners[$model] = $listeners; + } + public static function getListeners(string $model): array { return static::$listeners[$model] ?? []; } /** - * Clear all registered observers with the model. + * Clear all registered listeners. */ public static function clearListeners(): void { From 6f6bc8370f355cddc4a45d0a23fa0c7be745fe13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 15:55:22 +0800 Subject: [PATCH 101/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ce2cbc11..0d20dc646 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,10 @@ - [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Optimized server and Fixed middleware that user defined does not works. - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. - [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd +- [#441](https://github.com/hyperf-cloud/hyperf/pull/441) Automatically close the spare redis client when it is used in low frequency. ## Changed -- [#441](https://github.com/hyperf-cloud/hyperf/pull/441) Automatically close the spare redis client when it is used in low frequency. - [#437](https://github.com/hyperf-cloud/hyperf/pull/437) Changed `Hyperf\Testing\Client` handle exception handlers instead of throw an exception directly. ## Deleted From dabc9a50e055a26a14356fb142429fc51aea9c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Fri, 23 Aug 2019 15:58:08 +0800 Subject: [PATCH 102/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 171afa035..f48a37c1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ - [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Optimized server and Fixed middleware that user defined does not works. - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. - [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd -- [#420](https://github.com/hyperf-cloud/hyperf/pull/420) Added observer for model. +- [#420](https://github.com/hyperf-cloud/hyperf/pull/420) Added listener for model. ## Changed From 3d9d57c5fd612c5daa6cdcf5041219efb7d12e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 16:09:35 +0800 Subject: [PATCH 103/225] Fixed name. --- .../src/Collector/ListenerCollector.php | 4 ++-- .../src/Listener/ModelEventListener.php | 13 +++++-------- .../src/Listener/ModelHookEventListener.php | 2 +- src/model-listener/tests/AnnotationTest.php | 8 ++++---- ...rCollectorTest.php => ListenerCollectorTest.php} | 8 ++++---- 5 files changed, 16 insertions(+), 19 deletions(-) rename src/model-listener/tests/{ObserverCollectorTest.php => ListenerCollectorTest.php} (86%) diff --git a/src/model-listener/src/Collector/ListenerCollector.php b/src/model-listener/src/Collector/ListenerCollector.php index 7fe6febcd..f93dca340 100644 --- a/src/model-listener/src/Collector/ListenerCollector.php +++ b/src/model-listener/src/Collector/ListenerCollector.php @@ -36,12 +36,12 @@ class ListenerCollector ); } - public static function setListeners(string $model, array $listeners): void + public static function setListenersForModel(string $model, array $listeners): void { static::$listeners[$model] = $listeners; } - public static function getListeners(string $model): array + public static function getListenersForModel(string $model): array { return static::$listeners[$model] ?? []; } diff --git a/src/model-listener/src/Listener/ModelEventListener.php b/src/model-listener/src/Listener/ModelEventListener.php index 7152060f7..b9e09589b 100644 --- a/src/model-listener/src/Listener/ModelEventListener.php +++ b/src/model-listener/src/Listener/ModelEventListener.php @@ -42,25 +42,22 @@ class ModelEventListener implements ListenerInterface /** * @param Event $event - * @return Event */ public function process(object $event) { $model = $event->getModel(); $modelName = get_class($model); - $observers = ListenerCollector::getListeners($modelName); - foreach ($observers as $name) { + $listeners = ListenerCollector::getListenersForModel($modelName); + foreach ($listeners as $name) { if (! $this->container->has($name)) { continue; } - $observer = $this->container->get($name); - if (method_exists($observer, $event->getMethod())) { - $observer->{$event->getMethod()}($event); + $listener = $this->container->get($name); + if (method_exists($listener, $event->getMethod())) { + $listener->{$event->getMethod()}($event); } } - - return $event; } } diff --git a/src/model-listener/src/Listener/ModelHookEventListener.php b/src/model-listener/src/Listener/ModelHookEventListener.php index e49ca5caa..dd87262a6 100644 --- a/src/model-listener/src/Listener/ModelHookEventListener.php +++ b/src/model-listener/src/Listener/ModelHookEventListener.php @@ -33,6 +33,6 @@ class ModelHookEventListener implements ListenerInterface */ public function process(object $event) { - return $event->handle(); + $event->handle(); } } diff --git a/src/model-listener/tests/AnnotationTest.php b/src/model-listener/tests/AnnotationTest.php index 72c3b980c..29be9c6fe 100644 --- a/src/model-listener/tests/AnnotationTest.php +++ b/src/model-listener/tests/AnnotationTest.php @@ -35,21 +35,21 @@ class AnnotationTest extends TestCase $annotation = new ModelListener(['value' => ModelStub::class]); $annotation->collectClass('Foo'); - $this->assertSame(['Foo'], ListenerCollector::getListeners(ModelStub::class)); + $this->assertSame(['Foo'], ListenerCollector::getListenersForModel(ModelStub::class)); } public function testAnnotationCollectAssocArray() { $annotation = new ModelListener(['models' => [ModelStub::class]]); $annotation->collectClass('Foo'); - $this->assertSame(['Foo'], ListenerCollector::getListeners(ModelStub::class)); + $this->assertSame(['Foo'], ListenerCollector::getListenersForModel(ModelStub::class)); } public function testAnnotationCollectArray() { $annotation = new ModelListener(['value' => [ModelStub::class, 'ModelStub']]); $annotation->collectClass('Foo'); - $this->assertSame(['Foo'], ListenerCollector::getListeners(ModelStub::class)); - $this->assertSame(['Foo'], ListenerCollector::getListeners('ModelStub')); + $this->assertSame(['Foo'], ListenerCollector::getListenersForModel(ModelStub::class)); + $this->assertSame(['Foo'], ListenerCollector::getListenersForModel('ModelStub')); } } diff --git a/src/model-listener/tests/ObserverCollectorTest.php b/src/model-listener/tests/ListenerCollectorTest.php similarity index 86% rename from src/model-listener/tests/ObserverCollectorTest.php rename to src/model-listener/tests/ListenerCollectorTest.php index a7e2d5679..aceb46335 100644 --- a/src/model-listener/tests/ObserverCollectorTest.php +++ b/src/model-listener/tests/ListenerCollectorTest.php @@ -19,7 +19,7 @@ use PHPUnit\Framework\TestCase; * @internal * @coversNothing */ -class ObserverCollectorTest extends TestCase +class ListenerCollectorTest extends TestCase { protected function tearDown() { @@ -32,7 +32,7 @@ class ObserverCollectorTest extends TestCase { $class = 'HyperfTest\ModelListener\Stub\ModelStub'; ListenerCollector::register($class, 'ObserverClass'); - $this->assertSame(['ObserverClass'], ListenerCollector::getListeners($class)); + $this->assertSame(['ObserverClass'], ListenerCollector::getListenersForModel($class)); } public function testRegisterMoreThanOneObserver() @@ -41,7 +41,7 @@ class ObserverCollectorTest extends TestCase ListenerCollector::register($class, 'ObserverClass'); ListenerCollector::register($class, 'ObserverClass2'); ListenerCollector::register($class, 'ObserverClass3'); - $this->assertSame(['ObserverClass', 'ObserverClass2', 'ObserverClass3'], ListenerCollector::getListeners($class)); + $this->assertSame(['ObserverClass', 'ObserverClass2', 'ObserverClass3'], ListenerCollector::getListenersForModel($class)); } public function testClearObservables() @@ -51,6 +51,6 @@ class ObserverCollectorTest extends TestCase ListenerCollector::clearListeners(); - $this->assertSame([], ListenerCollector::getListeners($class)); + $this->assertSame([], ListenerCollector::getListenersForModel($class)); } } From 574ad4dc343fa17dfb2609c239d66a8e199d844f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 23 Aug 2019 16:14:24 +0800 Subject: [PATCH 104/225] Fixed bug for namespace. --- src/model-listener/src/Annotation/ModelListener.php | 2 +- src/model-listener/tests/AnnotationTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model-listener/src/Annotation/ModelListener.php b/src/model-listener/src/Annotation/ModelListener.php index 8b097f320..9bb7c94b9 100644 --- a/src/model-listener/src/Annotation/ModelListener.php +++ b/src/model-listener/src/Annotation/ModelListener.php @@ -10,7 +10,7 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\ModelListener; +namespace Hyperf\ModelListener\Annotation; use Hyperf\Di\Annotation\AbstractAnnotation; use Hyperf\ModelListener\Collector\ListenerCollector; diff --git a/src/model-listener/tests/AnnotationTest.php b/src/model-listener/tests/AnnotationTest.php index 29be9c6fe..1f08164f2 100644 --- a/src/model-listener/tests/AnnotationTest.php +++ b/src/model-listener/tests/AnnotationTest.php @@ -13,7 +13,7 @@ declare(strict_types=1); namespace HyperfTest\ModelListener; use Hyperf\ModelListener\Collector\ListenerCollector; -use Hyperf\ModelListener\ModelListener; +use Hyperf\ModelListener\Annotation\ModelListener; use HyperfTest\ModelListener\Stub\ModelStub; use PHPUnit\Framework\TestCase; From 87732da2436f264d2061263d08677528039234d9 Mon Sep 17 00:00:00 2001 From: ECE2 Date: Fri, 23 Aug 2019 17:15:48 +0800 Subject: [PATCH 105/225] Update exception-handler.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handle 方法返回 $response 变量拼写错误 --- doc/zh/exception-handler.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/exception-handler.md b/doc/zh/exception-handler.md index eb2bfa73f..68fb2ab38 100644 --- a/doc/zh/exception-handler.md +++ b/doc/zh/exception-handler.md @@ -57,7 +57,7 @@ class FooExceptionHandler extends ExceptionHandler } // 交给下一个异常处理器 - return $respose; + return $response; // 或者不做处理直接屏蔽异常 } From d641683bce7547ee12663ec30cb99252d184611a Mon Sep 17 00:00:00 2001 From: Ye Wenbin Date: Sat, 24 Aug 2019 07:58:53 +0800 Subject: [PATCH 106/225] fix #433: set open_http_protocol and open_http2_protocol to false when server type is tcp --- src/server/src/Port.php | 11 +++++++++++ src/server/src/Server.php | 5 ++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/server/src/Port.php b/src/server/src/Port.php index d93ce7ec3..a211aa72c 100644 --- a/src/server/src/Port.php +++ b/src/server/src/Port.php @@ -52,6 +52,7 @@ class Port public static function build(array $config) { $port = new static(); + self::filter($config); isset($config['name']) && $port->setName($config['name']); isset($config['type']) && $port->setType($config['type']); isset($config['host']) && $port->setHost($config['host']); @@ -138,4 +139,14 @@ class Port $this->settings = $settings; return $this; } + + private static function filter(array &$config) + { + if ($config['type'] == ServerInterface::SERVER_TCP) { + $config['settings'] = array_replace($config['settings'] ?? [], [ + 'open_http2_protocol' => false, + 'open_http_protocol' => false, + ]); + } + } } diff --git a/src/server/src/Server.php b/src/server/src/Server.php index d0ecb293e..65d672743 100644 --- a/src/server/src/Server.php +++ b/src/server/src/Server.php @@ -112,6 +112,9 @@ class Server implements ServerInterface } else { /** @var \Swoole\Server\Port $slaveServer */ $slaveServer = $this->server->addlistener($host, $port, $sockType); + if (! $slaveServer) { + throw new \RuntimeException("Failed to listen server port [{$host}:{$port}]"); + } $server->getSettings() && $slaveServer->set($server->getSettings()); $this->registerSwooleEvents($slaveServer, $callbacks, $name); ServerManager::add($name, [$type, $slaveServer]); @@ -177,7 +180,7 @@ class Server implements ServerInterface } /** - * @param Port|SwooleServer $server + * @param \Swoole\Server\Port|SwooleServer $server */ protected function registerSwooleEvents($server, array $events, string $serverName): void { From 3483eef5007f6b2bb512cc28508a4cf653ae99f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sat, 24 Aug 2019 11:15:25 +0800 Subject: [PATCH 107/225] Added testing. --- CHANGELOG.md | 4 +++ src/server/src/Port.php | 13 +++++--- src/server/tests/PortTest.php | 57 +++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 src/server/tests/PortTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index a588df631..b526d31f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ - [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Deleted class `Hyperf\JsonRpc\HttpServerFactory`, `Hyperf\HttpServer\ServerFactory`, `Hyperf\GrpcServer\ServerFactory`. - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Deleted deprecated method `AsyncQueue::delay`. +## Fixed + +- [#448](https://github.com/hyperf-cloud/hyperf/pull/448) Fixed TcpServer does not works, when has http or ws servers. + # v1.0.13 - TBD # v1.0.12 - 2019-08-21 diff --git a/src/server/src/Port.php b/src/server/src/Port.php index a211aa72c..943ad69bd 100644 --- a/src/server/src/Port.php +++ b/src/server/src/Port.php @@ -51,8 +51,9 @@ class Port public static function build(array $config) { + $config = self::filter($config); + $port = new static(); - self::filter($config); isset($config['name']) && $port->setName($config['name']); isset($config['type']) && $port->setType($config['type']); isset($config['host']) && $port->setHost($config['host']); @@ -140,13 +141,17 @@ class Port return $this; } - private static function filter(array &$config) + private static function filter(array $config): array { if ($config['type'] == ServerInterface::SERVER_TCP) { - $config['settings'] = array_replace($config['settings'] ?? [], [ + $default = [ 'open_http2_protocol' => false, 'open_http_protocol' => false, - ]); + ]; + + $config['settings'] = array_merge($default, $config['settings'] ?? []); } + + return $config; } } diff --git a/src/server/tests/PortTest.php b/src/server/tests/PortTest.php new file mode 100644 index 000000000..ae6ee9d1d --- /dev/null +++ b/src/server/tests/PortTest.php @@ -0,0 +1,57 @@ + 'http', + 'type' => Server::SERVER_HTTP, + ]); + + $this->assertSame([], $port->getSettings()); + + $port = Port::build([ + 'name' => 'tcp', + 'type' => Server::SERVER_TCP, + ]); + + $this->assertSame([ + 'open_http2_protocol' => false, + 'open_http_protocol' => false, + ], $port->getSettings()); + + $port = Port::build([ + 'name' => 'tcp', + 'type' => Server::SERVER_TCP, + 'settings' => [ + 'open_http2_protocol' => true, + ], + ]); + + $this->assertSame([ + 'open_http2_protocol' => true, + 'open_http_protocol' => false, + ], $port->getSettings()); + } +} From 44441e1862945e527e4fe72a2b1a40b1877afc6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Sun, 25 Aug 2019 01:29:35 +0800 Subject: [PATCH 108/225] Update Port.php --- src/server/src/Port.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/src/Port.php b/src/server/src/Port.php index 943ad69bd..a0a184a0d 100644 --- a/src/server/src/Port.php +++ b/src/server/src/Port.php @@ -143,7 +143,7 @@ class Port private static function filter(array $config): array { - if ($config['type'] == ServerInterface::SERVER_TCP) { + if ((int) $config['type'] === ServerInterface::SERVER_TCP) { $default = [ 'open_http2_protocol' => false, 'open_http_protocol' => false, From 9cb4e3694b82fa078e2bfb1ef207ff1f820bd964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Sun, 25 Aug 2019 01:32:05 +0800 Subject: [PATCH 109/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b526d31f2..2f48c33ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ ## Fixed -- [#448](https://github.com/hyperf-cloud/hyperf/pull/448) Fixed TcpServer does not works, when has http or ws servers. +- [#448](https://github.com/hyperf-cloud/hyperf/pull/448) Fixed TCP Server does not works when HTTP Server or WebSocket Server exists. # v1.0.13 - TBD From c1845bd5a5d0618a5ce76590534c43b732ebfbfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 25 Aug 2019 11:41:41 +0800 Subject: [PATCH 110/225] Added phpstan. --- .travis.yml | 1 + composer.json | 4 +++- phpstan.neon | 6 ++++++ src/json-rpc/src/HttpServer.php | 2 +- src/json-rpc/src/JsonRpcTransporter.php | 8 +++++++- src/rpc-server/src/RequestDispatcher.php | 3 ++- 6 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 phpstan.neon diff --git a/.travis.yml b/.travis.yml index 8b96a097a..e405a7cfd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,4 +44,5 @@ before_script: - composer config -g process-timeout 900 && composer update script: + - composer analyse - composer test diff --git a/composer.json b/composer.json index 76a1de1b5..acde40328 100644 --- a/composer.json +++ b/composer.json @@ -45,6 +45,7 @@ "malukenho/docheader": "^0.1.6", "mockery/mockery": "^1.0", "php-di/php-di": "^6.0", + "phpstan/phpstan": "^0.11.15", "phpunit/phpunit": "^7.0.0", "swoft/swoole-ide-helper": "dev-master", "symfony/property-access": "^4.3", @@ -270,7 +271,8 @@ "test-coverage": "phpunit --colors=always --coverage-clover clover.xml", "license-check": "docheader check src/ test/", "cs-fix": "php-cs-fixer fix $1", - "json-fix": "./bin/composer-json-fixer" + "json-fix": "./bin/composer-json-fixer", + "analyze": "phpstan analyse --memory-limit 300M -l 5 -c phpstan.neon ./src/json-rpc" }, "minimum-stability": "dev", "prefer-stable": true diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 000000000..e78e5a904 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,6 @@ +# Magic behaviour with __get, __set, __call and __callStatic is not exactly static analyser-friendly :) +# Fortunately, You can ingore it by the following config. +# +parameters: + excludes_analyse: + - %currentWorkingDirectory%/src/*/tests/* \ No newline at end of file diff --git a/src/json-rpc/src/HttpServer.php b/src/json-rpc/src/HttpServer.php index 55304dd36..a45a3d9ba 100644 --- a/src/json-rpc/src/HttpServer.php +++ b/src/json-rpc/src/HttpServer.php @@ -37,7 +37,7 @@ class HttpServer extends Server protected $protocol; /** - * @var \Hyperf\Rpc\Contract\PackerInterface + * @var \Hyperf\Contract\PackerInterface */ protected $packer; diff --git a/src/json-rpc/src/JsonRpcTransporter.php b/src/json-rpc/src/JsonRpcTransporter.php index a3f081fd7..a5e901d0a 100644 --- a/src/json-rpc/src/JsonRpcTransporter.php +++ b/src/json-rpc/src/JsonRpcTransporter.php @@ -43,6 +43,12 @@ class JsonRpcTransporter implements TransporterInterface */ private $recvTimeout = 5; + /** + * TODO: Set config. + * @var array + */ + private $config; + public function send(string $data) { $client = retry(2, function () use ($data) { @@ -67,7 +73,7 @@ class JsonRpcTransporter implements TransporterInterface $result = $client->connect($node->host, $node->port, $this->connectTimeout); if ($result === false && ($client->errCode == 114 or $client->errCode == 115)) { // Force close and reconnect to server. - $client->close(true); + $client->close(); throw new RuntimeException('Connect to server failed.'); } return $client; diff --git a/src/rpc-server/src/RequestDispatcher.php b/src/rpc-server/src/RequestDispatcher.php index c83e75ff6..b88ef1384 100644 --- a/src/rpc-server/src/RequestDispatcher.php +++ b/src/rpc-server/src/RequestDispatcher.php @@ -13,12 +13,13 @@ declare(strict_types=1); namespace Hyperf\RpcServer; use Hyperf\Dispatcher\AbstractDispatcher; +use Hyperf\Dispatcher\HttpDispatcher; use Hyperf\Dispatcher\HttpRequestHandler; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -class RequestDispatcher extends AbstractDispatcher +class RequestDispatcher extends HttpDispatcher { /** * @var ContainerInterface From ca2f54895fc8946ea540fdd5cc543a3596797a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 25 Aug 2019 11:47:10 +0800 Subject: [PATCH 111/225] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index acde40328..5397c8bc2 100644 --- a/composer.json +++ b/composer.json @@ -272,7 +272,7 @@ "license-check": "docheader check src/ test/", "cs-fix": "php-cs-fixer fix $1", "json-fix": "./bin/composer-json-fixer", - "analyze": "phpstan analyse --memory-limit 300M -l 5 -c phpstan.neon ./src/json-rpc" + "analyse": "phpstan analyse --memory-limit 300M -l 5 -c phpstan.neon ./src/json-rpc" }, "minimum-stability": "dev", "prefer-stable": true From 550e3859ee05d0700942d5e96332b6ff602d7335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 25 Aug 2019 11:54:57 +0800 Subject: [PATCH 112/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a588df631..ab8316112 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Added -- [#401](https://github.com/hyperf-cloud/hyperf/pull/401) Optimized server and Fixed middleware that user defined does not works. +- [#401](https://github.com/hyperf-cloud/hyperf/pull/401) [#447](https://github.com/hyperf-cloud/hyperf/issues/447) Optimized server and Fixed middleware that user defined does not works. - [#402](https://github.com/hyperf-cloud/hyperf/pull/402) Added Annotation AsyncQueueMessage. - [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd - [#420](https://github.com/hyperf-cloud/hyperf/pull/420) Added listener for model. From a2409638bb76967d1457c1bbc3da069da5e0df36 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Mon, 26 Aug 2019 11:45:38 +0800 Subject: [PATCH 113/225] Added Response sendfile --- src/http-message/src/Server/Response.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/http-message/src/Server/Response.php b/src/http-message/src/Server/Response.php index 95c1bfa07..03b853180 100755 --- a/src/http-message/src/Server/Response.php +++ b/src/http-message/src/Server/Response.php @@ -35,6 +35,11 @@ class Response extends \Hyperf\HttpMessage\Base\Response $this->swooleResponse = $response; } + /** + * @var bool + */ + protected $is_end = false; + /** * Handle response and send. */ @@ -49,6 +54,25 @@ class Response extends \Hyperf\HttpMessage\Base\Response $this->swooleResponse->end($this->getBody()->getContents()); } + /** + * Handle response and sendfile. + * @param string $file_name + * @param string $content_type + */ + public function sendfile(string $file_name, string $content_type = 'application/octet-stream') + { + $response = $this->getSwooleResponse(); + $response->setStatusCode(200); + $response->setHeader('Content-Description', 'File Transfer'); + $response->setHeader('Content-Type', $content_type); + $response->setHeader('Content-Disposition', 'attachment; filename=' . basename($file_name)); + $response->setHeader('Content-Transfer-Encoding', 'binary'); + $response->setHeader('Pragma', 'public'); + if ($response->sendfile($file_name)) { + $this->is_end = true; + } + } + /** * Returns an instance with body content. */ From 11668264116b2f8c1e0782937d014e74eb2bc577 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Mon, 26 Aug 2019 12:04:57 +0800 Subject: [PATCH 114/225] Added Response sendfile --- doc/zh/response.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/zh/response.md b/doc/zh/response.md index f81e606b9..c80664ba1 100644 --- a/doc/zh/response.md +++ b/doc/zh/response.md @@ -126,3 +126,18 @@ class IndexController ## 分块传输编码 Chunk ## 返回文件下载 +```php +sendfile('/var/www/file.csv'); + } +} +``` \ No newline at end of file From 50ea6ef327a620f95b1dd48d4b2376051d96b568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 26 Aug 2019 12:30:14 +0800 Subject: [PATCH 115/225] Optimized annotation cache. --- .../src/Collector/MetadataCacheCollector.php | 76 +++++++++++++++++++ src/di/src/Collector/MetadataCollector.php | 76 +++++++++++++++++++ .../Collector/MetadataCollectorInterface.php | 44 +++++++++++ src/di/tests/MetadataCollectorTest.php | 12 +++ 4 files changed, 208 insertions(+) create mode 100644 src/di/src/Collector/MetadataCacheCollector.php create mode 100644 src/di/src/Collector/MetadataCollector.php create mode 100644 src/di/src/Collector/MetadataCollectorInterface.php create mode 100644 src/di/tests/MetadataCollectorTest.php diff --git a/src/di/src/Collector/MetadataCacheCollector.php b/src/di/src/Collector/MetadataCacheCollector.php new file mode 100644 index 000000000..8da55eab5 --- /dev/null +++ b/src/di/src/Collector/MetadataCacheCollector.php @@ -0,0 +1,76 @@ +container = $container; + } + + public function addCollector(string $collector) + { + $this->collectors = array_unique(array_merge( + $this->collectors, + [$collector] + )); + } + + public function serialize(): string + { + $metadata = []; + foreach ($this->collectors as $collector) { + if ($this->container->has($collector)) { + $class = $this->container->get($collector); + if ($class instanceof MetadataCollectorInterface) { + $metadata[$collector] = $class->getMetadata(); + } + } + } + + return serialize($metadata); + } + + public function unserialize($serialized): void + { + $metadatas = unserialize($serialized); + + foreach ($metadatas as $collector => $metadata) { + if (! $this->container->has($collector)) { + throw new NotFoundException(sprintf('Collector %s not found in Container.')); + } + + $class = $this->container->get($collector); + if (! $class instanceof MetadataCollectorInterface) { + throw new InvalidDefinitionException(sprintf('Collector %s is not instanceof MetadataCollectorInterface.')); + } + + $class->setMetadata($metadata); + } + } +} diff --git a/src/di/src/Collector/MetadataCollector.php b/src/di/src/Collector/MetadataCollector.php new file mode 100644 index 000000000..0be440e77 --- /dev/null +++ b/src/di/src/Collector/MetadataCollector.php @@ -0,0 +1,76 @@ +container = $container; + + $container->get(MetadataCacheCollector::class)->addCollector(static::class); + } + + /** + * Retrieve the metadata via key. + * @param null|mixed $default + */ + public function get(string $key, $default = null) + { + return Arr::get($this->metadata, $key) ?? $default; + } + + /** + * Set the metadata to holder. + * @param mixed $value + */ + public function set(string $key, $value): void + { + Arr::set($this->metadata, $key, $value); + } + + /** + * Determine if the metadata exist. + * If exist will return true, otherwise return false. + */ + public function has(string $key): bool + { + return Arr::has($this->metadata, $key); + } + + /** + * Get all metadata. + */ + public function getMetadata(): array + { + return $this->metadata; + } + + public function setMetadata(array $metadata): void + { + $this->metadata = $metadata; + } +} diff --git a/src/di/src/Collector/MetadataCollectorInterface.php b/src/di/src/Collector/MetadataCollectorInterface.php new file mode 100644 index 000000000..526f616b6 --- /dev/null +++ b/src/di/src/Collector/MetadataCollectorInterface.php @@ -0,0 +1,44 @@ + Date: Mon, 26 Aug 2019 12:46:17 +0800 Subject: [PATCH 116/225] Optimized di. --- src/di/src/Annotation/Aspect.php | 7 +++-- src/di/tests/AopAspectTest.php | 22 ++++++++++++++++ src/di/tests/Stub/Foo2Aspect.php | 36 +++++++++++++++++++++++++ src/di/tests/Stub/FooAspect.php | 45 ++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 src/di/tests/Stub/Foo2Aspect.php create mode 100644 src/di/tests/Stub/FooAspect.php diff --git a/src/di/src/Annotation/Aspect.php b/src/di/src/Annotation/Aspect.php index 2a865446b..8b9da2e62 100644 --- a/src/di/src/Annotation/Aspect.php +++ b/src/di/src/Annotation/Aspect.php @@ -21,9 +21,6 @@ use Hyperf\Di\Aop\AroundInterface; */ class Aspect extends AbstractAnnotation { - /** - * {@inheritdoc} - */ public function collectClass(string $className): void { // @TODO Add order property. @@ -33,7 +30,9 @@ class Aspect extends AbstractAnnotation $instance = $instantitor->instantiate($className); switch ($instance) { case $instance instanceof AroundInterface: - AspectCollector::setAround($className, $instance->classes, $instance->annotations); + $classes = property_exists($instance, 'classes') ? $instance->classes : []; + $annotations = property_exists($instance, 'annotations') ? $instance->annotations : []; + AspectCollector::setAround($className, $classes, $annotations); break; } } diff --git a/src/di/tests/AopAspectTest.php b/src/di/tests/AopAspectTest.php index e459ca0dc..8755d4e81 100644 --- a/src/di/tests/AopAspectTest.php +++ b/src/di/tests/AopAspectTest.php @@ -12,11 +12,15 @@ declare(strict_types=1); namespace HyperfTest\Di; +use Hyperf\Di\Annotation\Aspect as AspectAnnotation; use Hyperf\Di\Aop\Aspect; use Hyperf\Di\Aop\RewriteCollection; use HyperfTest\Di\Stub\AnnotationCollector; use HyperfTest\Di\Stub\AspectCollector; use HyperfTest\Di\Stub\DemoAnnotation; +use HyperfTest\Di\Stub\Foo; +use HyperfTest\Di\Stub\Foo2Aspect; +use HyperfTest\Di\Stub\FooAspect; use PHPUnit\Framework\TestCase; /** @@ -203,4 +207,22 @@ class AopAspectTest extends TestCase $this->assertFalse(Aspect::isMatch('Foo/Bar/Baz', 'method', $rule)); $this->assertFalse(Aspect::isMatch('Foo/Bar', 'test', $rule)); } + + public function testAspectAnnotation() + { + $annotation = new AspectAnnotation(); + + $annotation->collectClass(FooAspect::class); + $annotation->collectClass(Foo2Aspect::class); + + $this->assertSame([ + 'classes' => [Foo::class], + 'annotations' => [DemoAnnotation::class], + ], AspectCollector::getRule(FooAspect::class)); + + $this->assertSame([ + 'classes' => [Foo::class], + 'annotations' => [], + ], AspectCollector::getRule(Foo2Aspect::class)); + } } diff --git a/src/di/tests/Stub/Foo2Aspect.php b/src/di/tests/Stub/Foo2Aspect.php new file mode 100644 index 000000000..df1ac6bfd --- /dev/null +++ b/src/di/tests/Stub/Foo2Aspect.php @@ -0,0 +1,36 @@ + Date: Mon, 26 Aug 2019 13:31:20 +0800 Subject: [PATCH 117/225] Added proxy class generate testing. --- src/di/src/Annotation/AspectCollector.php | 4 +- src/di/src/Aop/ProceedingJoinPoint.php | 7 +- src/di/src/Aop/ProxyCallVisitor.php | 8 ++- src/di/tests/AstTest.php | 83 +++++++++++++++++++++++ src/di/tests/Stub/Ast/Bar.php | 46 +++++++++++++ src/di/tests/Stub/Ast/Bar2.php | 26 +++++++ src/di/tests/Stub/Ast/Foo.php | 17 +++++ 7 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 src/di/tests/AstTest.php create mode 100644 src/di/tests/Stub/Ast/Bar.php create mode 100644 src/di/tests/Stub/Ast/Bar2.php create mode 100644 src/di/tests/Stub/Ast/Foo.php diff --git a/src/di/src/Annotation/AspectCollector.php b/src/di/src/Annotation/AspectCollector.php index feac5a87d..b8aa6f8cc 100644 --- a/src/di/src/Annotation/AspectCollector.php +++ b/src/di/src/Annotation/AspectCollector.php @@ -28,8 +28,8 @@ class AspectCollector extends MetadataCollector public static function setAround(string $aspect, array $classes, array $annotations): void { - $classes && static::set('classes.' . $aspect, $classes); - $annotations && static::set('annotations.' . $aspect, $annotations); + static::set('classes.' . $aspect, $classes); + static::set('annotations.' . $aspect, $annotations); static::$aspectRules[$aspect] = [ 'classes' => $classes, 'annotations' => $annotations, diff --git a/src/di/src/Aop/ProceedingJoinPoint.php b/src/di/src/Aop/ProceedingJoinPoint.php index 1193b5f4f..a0a987abf 100644 --- a/src/di/src/Aop/ProceedingJoinPoint.php +++ b/src/di/src/Aop/ProceedingJoinPoint.php @@ -14,6 +14,7 @@ namespace Hyperf\Di\Aop; use Closure; use Hyperf\Di\Annotation\AnnotationCollector; +use Hyperf\Di\Exception\Exception; class ProceedingJoinPoint { @@ -43,7 +44,7 @@ class ProceedingJoinPoint public $originalMethod; /** - * @var Closure + * @var null|Closure */ public $pipe; @@ -61,6 +62,10 @@ class ProceedingJoinPoint public function process() { $closure = $this->pipe; + if (! $closure instanceof Closure) { + throw new Exception('The pipi is not instanceof \Closure'); + } + return $closure($this); } diff --git a/src/di/src/Aop/ProxyCallVisitor.php b/src/di/src/Aop/ProxyCallVisitor.php index bd32755ce..2e1539e5f 100644 --- a/src/di/src/Aop/ProxyCallVisitor.php +++ b/src/di/src/Aop/ProxyCallVisitor.php @@ -52,7 +52,7 @@ class ProxyCallVisitor extends NodeVisitorAbstract ]; /** - * @var Identifier + * @var null|Identifier */ private $class; @@ -78,7 +78,7 @@ class ProxyCallVisitor extends NodeVisitorAbstract continue; } if (! $namespace instanceof Namespace_) { - return; + break; } // Add current class namespace. $usedNamespace = [ @@ -112,6 +112,8 @@ class ProxyCallVisitor extends NodeVisitorAbstract } } } + + return null; } public function leaveNode(Node $node) @@ -134,7 +136,7 @@ class ProxyCallVisitor extends NodeVisitorAbstract break; case $node instanceof StaticPropertyFetch && $this->extends: // Rewrite parent::$staticProperty to ParentClass::$staticProperty. - if ($node->class && $node->class->toString() === 'parent') { + if ($node->class instanceof Node\Name && $node->class->toString() === 'parent') { $node->class = new Name($this->extends->toCodeString()); return $node; } diff --git a/src/di/tests/AstTest.php b/src/di/tests/AstTest.php new file mode 100644 index 000000000..b96b0efa8 --- /dev/null +++ b/src/di/tests/AstTest.php @@ -0,0 +1,83 @@ +proxy(Foo::class, $proxyClass); + + $this->assertEquals('proxy(Bar2::class, $proxyClass); + + $this->assertEquals('id = $id; + } + + public function getId(): int + { + return $this->id; + } + + public function setId(int $id): self + { + $this->id = $id; + return $this; + } + + public static function make() + { + return new static(0); + } + + public static function getItems() + { + return static::items; + } +} diff --git a/src/di/tests/Stub/Ast/Bar2.php b/src/di/tests/Stub/Ast/Bar2.php new file mode 100644 index 000000000..341c91969 --- /dev/null +++ b/src/di/tests/Stub/Ast/Bar2.php @@ -0,0 +1,26 @@ + Date: Mon, 26 Aug 2019 13:55:44 +0800 Subject: [PATCH 118/225] Optimized ProxyCallVisitor. --- src/di/src/Aop/ProxyCallVisitor.php | 22 +++++-------- src/di/src/Aop/ProxyClassNameVisitor.php | 2 +- src/di/tests/AstTest.php | 42 ++++++++++++++++++++++++ src/di/tests/Stub/Ast/Bar3.php | 21 ++++++++++++ src/di/tests/Stub/Ast/BarAspect.php | 28 ++++++++++++++++ 5 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 src/di/tests/Stub/Ast/Bar3.php create mode 100644 src/di/tests/Stub/Ast/BarAspect.php diff --git a/src/di/src/Aop/ProxyCallVisitor.php b/src/di/src/Aop/ProxyCallVisitor.php index 2e1539e5f..208983e1b 100644 --- a/src/di/src/Aop/ProxyCallVisitor.php +++ b/src/di/src/Aop/ProxyCallVisitor.php @@ -227,17 +227,17 @@ class ProxyCallVisitor extends NodeVisitorAbstract $class = $this->class->toString(); $staticCall = new StaticCall(new Name('self'), '__proxyCall', [ // OriginalClass::class - new ClassConstFetch(new Name($class), new Identifier('class')), + new Node\Arg(new ClassConstFetch(new Name($class), new Identifier('class'))), // __FUNCTION__ - new MagicConstFunction(), + new Node\Arg(new MagicConstFunction()), // self::getParamMap(OriginalClass::class, __FUNCTION, func_get_args()) - new StaticCall(new Name('self'), 'getParamsMap', [ - new ClassConstFetch(new Name($class), new Identifier('class')), - new MagicConstFunction(), - new FuncCall(new Name('func_get_args')), - ]), + new Node\Arg(new StaticCall(new Name('self'), 'getParamsMap', [ + new Node\Arg(new ClassConstFetch(new Name($class), new Identifier('class'))), + new Node\Arg(new MagicConstFunction()), + new Node\Arg(new FuncCall(new Name('func_get_args'))), + ])), // A closure that wrapped original method code. - new Closure([ + new Node\Arg(new Closure([ 'params' => value(function () use ($node) { // Transfer the variadic variable to normal variable at closure argument. ...$params => $parms $params = $node->getParams(); @@ -255,7 +255,7 @@ class ProxyCallVisitor extends NodeVisitorAbstract new Variable('__method__'), ], 'stmts' => $node->stmts, - ]), + ])), ]); $magicConstFunction = new Expression(new Assign(new Variable('__function__'), new Node\Scalar\MagicConst\Function_())); $magicConstMethod = new Expression(new Assign(new Variable('__method__'), new Node\Scalar\MagicConst\Method())); @@ -277,10 +277,6 @@ class ProxyCallVisitor extends NodeVisitorAbstract private function shouldRewrite(ClassMethod $node) { - if (! $node->name) { - return false; - } - $rewriteCollection = Aspect::parse($this->classname); return $rewriteCollection->shouldRewrite($node->name->toString()); diff --git a/src/di/src/Aop/ProxyClassNameVisitor.php b/src/di/src/Aop/ProxyClassNameVisitor.php index adda63a7f..7c6cfe05a 100644 --- a/src/di/src/Aop/ProxyClassNameVisitor.php +++ b/src/di/src/Aop/ProxyClassNameVisitor.php @@ -35,7 +35,7 @@ class ProxyClassNameVisitor extends NodeVisitorAbstract { // Rewirte the class name and extends the original class. if ($node instanceof Node\Stmt\Class_ && ! $node->isAnonymous()) { - $node->extends = $node->name; + $node->extends = new Node\Name($node->name->name); $node->name = new Node\Identifier($this->proxyClassName); return $node; } diff --git a/src/di/tests/AstTest.php b/src/di/tests/AstTest.php index b96b0efa8..349344cca 100644 --- a/src/di/tests/AstTest.php +++ b/src/di/tests/AstTest.php @@ -13,7 +13,10 @@ declare(strict_types=1); namespace HyperfTest\Di; use Hyperf\Di\Aop\Ast; +use HyperfTest\Di\Stub\AspectCollector; use HyperfTest\Di\Stub\Ast\Bar2; +use HyperfTest\Di\Stub\Ast\Bar3; +use HyperfTest\Di\Stub\Ast\BarAspect; use HyperfTest\Di\Stub\Ast\Foo; use PHPUnit\Framework\TestCase; @@ -78,6 +81,45 @@ class Bar2Froxy extends Bar2 { return Bar::$items; } +}', $code); + } + + public function testRewriteMethods() + { + $aspect = BarAspect::class; + + AspectCollector::setAround($aspect, [ + Bar3::class, + ], []); + + $ast = new Ast(); + $proxyClass = Bar3::class . 'Froxy'; + $code = $ast->proxy(Bar3::class, $proxyClass); + + $this->assertEquals('process(); + } +} From afb91624effb04a3fd8e84e10de7978861023bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 26 Aug 2019 14:50:53 +0800 Subject: [PATCH 119/225] Optimized code. --- phpstan.neon | 7 ++++++- src/di/src/Container.php | 8 ++----- src/di/src/Definition/DefinitionSource.php | 3 +-- .../Definition/DefinitionSourceInterface.php | 2 +- src/di/src/Definition/FactoryDefinition.php | 2 +- src/di/src/ProxyFactory.php | 16 +++++--------- src/di/src/Resolver/ParameterResolver.php | 2 +- src/di/src/Resolver/ResolverDispatcher.php | 4 ++-- src/di/tests/DefinitionSourceTest.php | 11 ++++++++++ src/di/tests/Stub/FooFactory.php | 21 +++++++++++++++++++ 10 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 src/di/tests/Stub/FooFactory.php diff --git a/phpstan.neon b/phpstan.neon index e78e5a904..8a8426421 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,5 +2,10 @@ # Fortunately, You can ingore it by the following config. # parameters: + bootstrap: "bootstrap.php" + ignoreErrors: + - "#will always evaluate to false#" + - "#Result of && is always false.#" excludes_analyse: - - %currentWorkingDirectory%/src/*/tests/* \ No newline at end of file + - %currentWorkingDirectory%/src/*/tests/* + diff --git a/src/di/src/Container.php b/src/di/src/Container.php index 8286d82e1..7f19a524d 100644 --- a/src/di/src/Container.php +++ b/src/di/src/Container.php @@ -17,7 +17,6 @@ use Hyperf\Di\Definition\ObjectDefinition; use Hyperf\Di\Exception\NotFoundException; use Hyperf\Di\Resolver\ResolverDispatcher; use Hyperf\Dispatcher\Exceptions\InvalidArgumentException; -use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; @@ -61,7 +60,7 @@ class Container implements ContainerInterface { $this->definitionSource = $definitionSource; $this->definitionResolver = new ResolverDispatcher($this); - $this->proxyFactory = new ProxyFactory($this); + $this->proxyFactory = new ProxyFactory(); // Auto-register the container. $this->resolvedEntries = [ self::class => $this, @@ -97,8 +96,6 @@ class Container implements ContainerInterface * Finds an entry of the container by its identifier and returns it. * * @param string $name identifier of the entry to look for - * @throws NotFoundExceptionInterface no entry was found for **this** identifier - * @throws ContainerExceptionInterface error while retrieving the entry * @return mixed entry */ public function get($name) @@ -116,8 +113,7 @@ class Container implements ContainerInterface * Returns false otherwise. * `has($name)` returning true does not mean that `get($name)` will not throw an exception. * It does however mean that `get($name)` will not throw a `NotFoundExceptionInterface`. - * - * @param string $name identifier of the entry to look for + * @param mixed $name */ public function has($name): bool { diff --git a/src/di/src/Definition/DefinitionSource.php b/src/di/src/Definition/DefinitionSource.php index b7daba97d..fa1097c23 100644 --- a/src/di/src/Definition/DefinitionSource.php +++ b/src/di/src/Definition/DefinitionSource.php @@ -149,8 +149,7 @@ class DefinitionSource implements DefinitionSourceInterface } /** - * @param array|callable|string $definitions - * @param mixed $definition + * @param array|callable|string $definition */ private function normalizeDefinition(string $identifier, $definition): ?DefinitionInterface { diff --git a/src/di/src/Definition/DefinitionSourceInterface.php b/src/di/src/Definition/DefinitionSourceInterface.php index 03bcd2078..eed3d0394 100644 --- a/src/di/src/Definition/DefinitionSourceInterface.php +++ b/src/di/src/Definition/DefinitionSourceInterface.php @@ -20,7 +20,7 @@ interface DefinitionSourceInterface * Returns the DI definition for the entry name. * * @throws InvalidDefinitionException an invalid definition was found - * @return null|array + * @return null|DefinitionInterface */ public function getDefinition(string $name); diff --git a/src/di/src/Definition/FactoryDefinition.php b/src/di/src/Definition/FactoryDefinition.php index 1e368161d..eb4b8b486 100644 --- a/src/di/src/Definition/FactoryDefinition.php +++ b/src/di/src/Definition/FactoryDefinition.php @@ -20,7 +20,7 @@ class FactoryDefinition implements DefinitionInterface private $name; /** - * @var callable + * @var callable|string */ private $factory; diff --git a/src/di/src/ProxyFactory.php b/src/di/src/ProxyFactory.php index 9605c2423..e54638a07 100644 --- a/src/di/src/ProxyFactory.php +++ b/src/di/src/ProxyFactory.php @@ -13,7 +13,6 @@ declare(strict_types=1); namespace Hyperf\Di; use Hyperf\Di\Aop\Ast; -use Hyperf\Di\Definition\FactoryDefinition; use Hyperf\Di\Definition\ObjectDefinition; use Hyperf\Utils\Coroutine\Locker as CoLocker; @@ -40,16 +39,11 @@ class ProxyFactory if (isset(static::$map[$identifier])) { return static::$map[$identifier]; } - $proxyIdentifier = null; - if ($definition instanceof FactoryDefinition) { - $proxyIdentifier = $definition->getFactory() . '_' . md5($definition->getFactory()); - $proxyIdentifier && $definition->setTarget($proxyIdentifier); - $this->loadProxy($definition->getName(), $definition->getFactory()); - } elseif ($definition instanceof ObjectDefinition) { - $proxyIdentifier = $definition->getClassName() . '_' . md5($definition->getClassName()); - $definition->setProxyClassName($proxyIdentifier); - $this->loadProxy($definition->getClassName(), $definition->getProxyClassName()); - } + + $proxyIdentifier = $definition->getClassName() . '_' . md5($definition->getClassName()); + $definition->setProxyClassName($proxyIdentifier); + $this->loadProxy($definition->getClassName(), $definition->getProxyClassName()); + static::$map[$identifier] = $definition; return static::$map[$identifier]; } diff --git a/src/di/src/Resolver/ParameterResolver.php b/src/di/src/Resolver/ParameterResolver.php index bfee0b7af..6729bd503 100644 --- a/src/di/src/Resolver/ParameterResolver.php +++ b/src/di/src/Resolver/ParameterResolver.php @@ -21,7 +21,7 @@ use ReflectionParameter; class ParameterResolver { /** - * @var DefinitionInterface + * @var ResolverInterface */ private $definitionResolver; diff --git a/src/di/src/Resolver/ResolverDispatcher.php b/src/di/src/Resolver/ResolverDispatcher.php index baaf7d89b..e32ec3791 100644 --- a/src/di/src/Resolver/ResolverDispatcher.php +++ b/src/di/src/Resolver/ResolverDispatcher.php @@ -23,12 +23,12 @@ use RuntimeException; class ResolverDispatcher implements ResolverInterface { /** - * @var ObjectResolver + * @var null|ObjectResolver */ protected $objectResolver; /** - * @var FactoryResolver + * @var null|FactoryResolver */ protected $factoryResolver; diff --git a/src/di/tests/DefinitionSourceTest.php b/src/di/tests/DefinitionSourceTest.php index 6630ca941..15c1116a4 100644 --- a/src/di/tests/DefinitionSourceTest.php +++ b/src/di/tests/DefinitionSourceTest.php @@ -15,6 +15,8 @@ namespace HyperfTest\Di; use Hyperf\Di\Annotation\Scanner; use Hyperf\Di\Container; use Hyperf\Di\Definition\DefinitionSource; +use HyperfTest\Di\Stub\Foo; +use HyperfTest\Di\Stub\FooFactory; use PHPUnit\Framework\TestCase; /** @@ -31,4 +33,13 @@ class DefinitionSourceTest extends TestCase }); $this->assertEquals('bar', $container->get('Foo')); } + + public function testDefinitionFactory() + { + $container = new Container(new DefinitionSource([], [], new Scanner())); + $container->getDefinitionSource()->addDefinition('Foo', FooFactory::class); + + $foo = $container->get('Foo'); + $this->assertInstanceOf(Foo::class, $foo); + } } diff --git a/src/di/tests/Stub/FooFactory.php b/src/di/tests/Stub/FooFactory.php new file mode 100644 index 000000000..9fdcd1d97 --- /dev/null +++ b/src/di/tests/Stub/FooFactory.php @@ -0,0 +1,21 @@ + Date: Mon, 26 Aug 2019 14:51:04 +0800 Subject: [PATCH 120/225] Update --- .travis.yml | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e405a7cfd..823d4d795 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,5 +44,5 @@ before_script: - composer config -g process-timeout 900 && composer update script: - - composer analyse + - composer analyse src/di src/json-rpc - composer test diff --git a/composer.json b/composer.json index 5397c8bc2..8c8bbbc4c 100644 --- a/composer.json +++ b/composer.json @@ -272,7 +272,7 @@ "license-check": "docheader check src/ test/", "cs-fix": "php-cs-fixer fix $1", "json-fix": "./bin/composer-json-fixer", - "analyse": "phpstan analyse --memory-limit 300M -l 5 -c phpstan.neon ./src/json-rpc" + "analyse": "phpstan analyse --memory-limit 300M -l 4 -c phpstan.neon" }, "minimum-stability": "dev", "prefer-stable": true From b2044339d007632fb3c89f8630b22e91838539e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 26 Aug 2019 15:01:49 +0800 Subject: [PATCH 121/225] Added ProxyFactory into Container. --- composer.json | 2 +- src/di/src/Container.php | 1 + src/di/src/Resolver/ObjectResolver.php | 13 ++++++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 8c8bbbc4c..fec4fe375 100644 --- a/composer.json +++ b/composer.json @@ -272,7 +272,7 @@ "license-check": "docheader check src/ test/", "cs-fix": "php-cs-fixer fix $1", "json-fix": "./bin/composer-json-fixer", - "analyse": "phpstan analyse --memory-limit 300M -l 4 -c phpstan.neon" + "analyse": "phpstan analyse --memory-limit 300M -l 5 -c phpstan.neon" }, "minimum-stability": "dev", "prefer-stable": true diff --git a/src/di/src/Container.php b/src/di/src/Container.php index 7f19a524d..dc0d0984a 100644 --- a/src/di/src/Container.php +++ b/src/di/src/Container.php @@ -65,6 +65,7 @@ class Container implements ContainerInterface $this->resolvedEntries = [ self::class => $this, ContainerInterface::class => $this, + ProxyFactory::class => $this->proxyFactory, ]; } diff --git a/src/di/src/Resolver/ObjectResolver.php b/src/di/src/Resolver/ObjectResolver.php index e556ba2bf..a7818f3e1 100644 --- a/src/di/src/Resolver/ObjectResolver.php +++ b/src/di/src/Resolver/ObjectResolver.php @@ -12,7 +12,6 @@ declare(strict_types=1); namespace Hyperf\Di\Resolver; -use Hyperf\Di\Container; use Hyperf\Di\Definition\DefinitionInterface; use Hyperf\Di\Definition\ObjectDefinition; use Hyperf\Di\Definition\PropertyInjection; @@ -48,14 +47,12 @@ class ObjectResolver implements ResolverInterface /** * ObjectResolver constructor. - * - * @param Container $container */ public function __construct(ContainerInterface $container, ResolverInterface $definitionResolver) { $this->container = $container; $this->definitionResolver = $definitionResolver; - $this->proxyFactory = $container->getProxyFactory(); + $this->proxyFactory = $container->get(ProxyFactory::class); $this->parameterResolver = new ParameterResolver($definitionResolver); } @@ -64,12 +61,18 @@ class ObjectResolver implements ResolverInterface * * @param DefinitionInterface $definition object that defines how the value should be obtained * @param array $parameters optional parameters to use to build the entry - * @throws DependencyException * @throws InvalidDefinitionException + * @throws DependencyException * @return mixed value obtained from the definition */ public function resolve(DefinitionInterface $definition, array $parameters = []) { + if (! $definition instanceof ObjectDefinition) { + throw InvalidDefinitionException::create( + $definition, + sprintf('Entry "%s" cannot be resolved: the class is not instanceof ObjectDefinition', $definition->getName()) + ); + } return $this->createInstance($definition, $parameters); } From 22a359934a3b6e7968878acc9bd8d1733e4c5804 Mon Sep 17 00:00:00 2001 From: xiabin <276147613@qq.com> Date: Mon, 26 Aug 2019 16:46:52 +0800 Subject: [PATCH 122/225] Update middleware.md --- doc/zh/middleware/middleware.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/middleware/middleware.md b/doc/zh/middleware/middleware.md index 0522ca59d..0b124a168 100644 --- a/doc/zh/middleware/middleware.md +++ b/doc/zh/middleware/middleware.md @@ -120,7 +120,7 @@ class IndexController #### 定义方法级别的中间件 在通过配置文件的方式配置中间件时定义到方法级别上很简单,那么要通过注解的形式定义到方法级别呢?您只需将注解直接定义到方法上即可。 -方法级别上的中间件会优先于类级别的中间件,我们通过代码来举例一下: +类级别上的中间件会优先于方法级别的中间件,我们通过代码来举例一下: ```php Date: Mon, 26 Aug 2019 19:21:37 +0800 Subject: [PATCH 123/225] fixed if is_end --- src/http-message/src/Server/Response.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http-message/src/Server/Response.php b/src/http-message/src/Server/Response.php index 03b853180..e9a312db9 100755 --- a/src/http-message/src/Server/Response.php +++ b/src/http-message/src/Server/Response.php @@ -45,7 +45,7 @@ class Response extends \Hyperf\HttpMessage\Base\Response */ public function send() { - if (! $this->getSwooleResponse()) { + if ($this->is_end || !$this->getSwooleResponse()) { return; } @@ -121,7 +121,7 @@ class Response extends \Hyperf\HttpMessage\Base\Response /* * Cookies */ - foreach ((array) $this->cookies as $domain => $paths) { + foreach ((array)$this->cookies as $domain => $paths) { foreach ($paths ?? [] as $path => $item) { foreach ($item ?? [] as $name => $cookie) { if ($cookie instanceof Cookie) { From bbf70756e5aefe35effe05f8645ea47e8f027075 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 27 Aug 2019 09:56:02 +0800 Subject: [PATCH 124/225] optimize canonical naming --- src/http-message/src/Server/Response.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/http-message/src/Server/Response.php b/src/http-message/src/Server/Response.php index e9a312db9..dde95b4ca 100755 --- a/src/http-message/src/Server/Response.php +++ b/src/http-message/src/Server/Response.php @@ -38,14 +38,14 @@ class Response extends \Hyperf\HttpMessage\Base\Response /** * @var bool */ - protected $is_end = false; + protected $isEnd = false; /** * Handle response and send. */ public function send() { - if ($this->is_end || !$this->getSwooleResponse()) { + if ($this->isEnd || !$this->getSwooleResponse()) { return; } @@ -69,7 +69,7 @@ class Response extends \Hyperf\HttpMessage\Base\Response $response->setHeader('Content-Transfer-Encoding', 'binary'); $response->setHeader('Pragma', 'public'); if ($response->sendfile($file_name)) { - $this->is_end = true; + $this->isEnd = true; } } From 9ea6c2c07834393e3f4344672b5d51f5eb4ec1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 11:28:46 +0800 Subject: [PATCH 125/225] Update docker-swarm.md --- doc/zh/tutorial/docker-swarm.md | 75 +++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/doc/zh/tutorial/docker-swarm.md b/doc/zh/tutorial/docker-swarm.md index 5ac9157ac..cf27a78c9 100644 --- a/doc/zh/tutorial/docker-swarm.md +++ b/doc/zh/tutorial/docker-swarm.md @@ -100,6 +100,7 @@ docker network create \ --driver overlay \ --subnet 10.0.0.0/24 \ --opt encrypted \ +--attachable \ default-network ``` @@ -120,6 +121,14 @@ $ docker swarm join --token ip:2377 > 其他与 builder 一致,但是 tag 却不能一样。线上环境可以设置为 tags,测试环境设置为 test +## 安装其他应用 + +以下以 `Mysql` 为例,直接使用上述 `network`,支持容器内使用 name 互调。 + +``` +docker run --name mysql -v /srv/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=xxxx -p 3306:3306 --rm --network default-network -d mysql:5.7 +``` + ## 安装 Portainer [Portainer](https://github.com/portainer/portainer) @@ -226,6 +235,72 @@ REDIS_DB=0 curl http://127.0.0.1:9501/ ``` +## 安装 KONG 网关 + +通常情况下,Swarm集群是不会直接对外的,所以我们这里推荐使用 `KONG` 作为网关。 +还有另外一个原因,那就是 `Swarm` 的 `Ingress网络` 设计上有缺陷,所以在连接不复用的情况下,会有并发瓶颈,具体请查看对应 `Issue` [#35082](https://github.com/moby/moby/issues/35082) +而 `KONG` 作为网关,默认情况下就会复用后端的连接,所以会极大减缓上述问题。 + +### 安装数据库 + +``` +docker run -d --name kong-database \ + --network=default-network \ + -p 5432:5432 \ + -e "POSTGRES_USER=kong" \ + -e "POSTGRES_DB=kong" \ + postgres:9.6 +``` + +### 安装网关 + +初始化数据库 + +``` +docker run --rm \ + --network=default-network \ + -e "KONG_DATABASE=postgres" \ + -e "KONG_PG_HOST=kong-database" \ + -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \ + kong:latest kong migrations bootstrap +``` + +启动 + +``` +docker run -d --name kong \ + --network=default-network \ + -e "KONG_DATABASE=postgres" \ + -e "KONG_PG_HOST=kong-database" \ + -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \ + -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \ + -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \ + -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \ + -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \ + -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \ + -p 8000:8000 \ + -p 8443:8443 \ + -p 8001:8001 \ + -p 8444:8444 \ + kong:latest +``` + +### 安装 KONG Dashboard + +> 暂时 `Docker` 中没有更新 `v3.6.0` 所以最新版的 `KONG` 可能无法使用 + +``` +docker run --rm --network=default-network -p 8080:8080 -d --name kong-dashboard pgbi/kong-dashboard start \ + --kong-url http://kong:8001 \ + --basic-auth user1=password1 user2=password2 +``` + +### 配置 + +接下来只需要把部署 `KONG` 的机器 `IP` 对外,然后配置 `Service` 即可。 +如果机器直接对外,最好只开放 `80` `443` 端口,然后把 `Kong` 容器的 `8000` 和 `8443` 映射到 `80` 和 `443` 上。 +当然,如果使用了 `SLB` 等负载均衡,就直接通过负载均衡,把 `80` 和 `443` 映射到 `KONG` 所在几台机器的 `8000` `8443` 上。 + ## 意外情况 ### fatal: git fetch-pack: expected shallow list From f5c381bc5b53566f25d569b2d0ef1b68530859d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 13:30:24 +0800 Subject: [PATCH 126/225] Optimized phpstan.neon --- composer.json | 2 +- phpstan.neon | 83 ++++++++++++++++++++++++++++- src/di/src/Aop/ProxyCallVisitor.php | 4 ++ src/di/src/Container.php | 3 +- 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index fec4fe375..396c5e72f 100644 --- a/composer.json +++ b/composer.json @@ -272,7 +272,7 @@ "license-check": "docheader check src/ test/", "cs-fix": "php-cs-fixer fix $1", "json-fix": "./bin/composer-json-fixer", - "analyse": "phpstan analyse --memory-limit 300M -l 5 -c phpstan.neon" + "analyse": "phpstan analyse --memory-limit 300M -l 3 -c phpstan.neon" }, "minimum-stability": "dev", "prefer-stable": true diff --git a/phpstan.neon b/phpstan.neon index 8a8426421..23633bb5c 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,11 +1,92 @@ # Magic behaviour with __get, __set, __call and __callStatic is not exactly static analyser-friendly :) # Fortunately, You can ingore it by the following config. # +rules: + - PHPStan\Rules\Arrays\DeadForeachRule + - PHPStan\Rules\Comparison\BooleanOrConstantConditionRule + - PHPStan\Rules\Comparison\ElseIfConstantConditionRule + - PHPStan\Rules\Comparison\IfConstantConditionRule + - PHPStan\Rules\Comparison\TernaryOperatorConstantConditionRule + parameters: bootstrap: "bootstrap.php" + checkFunctionArgumentTypes: true + checkArgumentsPassedByReference: true + featureToggles: + deadCatchesRule: false + noopRule: false + tooWideTypehints: false + unreachableStatement: false ignoreErrors: - "#will always evaluate to false#" - - "#Result of && is always false.#" excludes_analyse: - %currentWorkingDirectory%/src/*/tests/* +conditionalTags: + PHPStan\Rules\Exceptions\DeadCatchRule: + phpstan.rules.rule: %featureToggles.deadCatchesRule% + PHPStan\Rules\DeadCode\NoopRule: + phpstan.rules.rule: %featureToggles.noopRule% + PHPStan\Rules\DeadCode\UnreachableStatementRule: + phpstan.rules.rule: %featureToggles.unreachableStatement% + PHPStan\Rules\TooWideTypehints\TooWideClosureReturnTypehintRule: + phpstan.rules.rule: %featureToggles.tooWideTypehints% + PHPStan\Rules\TooWideTypehints\TooWideFunctionReturnTypehintRule: + phpstan.rules.rule: %featureToggles.tooWideTypehints% + PHPStan\Rules\TooWideTypehints\TooWidePrivateMethodReturnTypehintRule: + phpstan.rules.rule: %featureToggles.tooWideTypehints% + +services: + - + class: PHPStan\Rules\Classes\ImpossibleInstanceOfRule + arguments: + checkAlwaysTrueInstanceof: %checkAlwaysTrueInstanceof% + tags: + - phpstan.rules.rule + + - + class: PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRule + arguments: + checkAlwaysTrueCheckTypeFunctionCall: %checkAlwaysTrueCheckTypeFunctionCall% + tags: + - phpstan.rules.rule + + - + class: PHPStan\Rules\Comparison\ImpossibleCheckTypeMethodCallRule + arguments: + checkAlwaysTrueCheckTypeFunctionCall: %checkAlwaysTrueCheckTypeFunctionCall% + tags: + - phpstan.rules.rule + + - + class: PHPStan\Rules\Comparison\ImpossibleCheckTypeStaticMethodCallRule + arguments: + checkAlwaysTrueCheckTypeFunctionCall: %checkAlwaysTrueCheckTypeFunctionCall% + tags: + - phpstan.rules.rule + + - + class: PHPStan\Rules\Comparison\StrictComparisonOfDifferentTypesRule + arguments: + checkAlwaysTrueStrictComparison: %checkAlwaysTrueStrictComparison% + tags: + - phpstan.rules.rule + + - + class: PHPStan\Rules\Exceptions\DeadCatchRule + + - + class: PHPStan\Rules\DeadCode\NoopRule + + - + class: PHPStan\Rules\DeadCode\UnreachableStatementRule + + - + class: PHPStan\Rules\TooWideTypehints\TooWideClosureReturnTypehintRule + + - + class: PHPStan\Rules\TooWideTypehints\TooWideFunctionReturnTypehintRule + + - + class: PHPStan\Rules\TooWideTypehints\TooWidePrivateMethodReturnTypehintRule + diff --git a/src/di/src/Aop/ProxyCallVisitor.php b/src/di/src/Aop/ProxyCallVisitor.php index 208983e1b..9afbafb46 100644 --- a/src/di/src/Aop/ProxyCallVisitor.php +++ b/src/di/src/Aop/ProxyCallVisitor.php @@ -277,6 +277,10 @@ class ProxyCallVisitor extends NodeVisitorAbstract private function shouldRewrite(ClassMethod $node) { + if (! $node->name) { + return false; + } + $rewriteCollection = Aspect::parse($this->classname); return $rewriteCollection->shouldRewrite($node->name->toString()); diff --git a/src/di/src/Container.php b/src/di/src/Container.php index dc0d0984a..a6cace571 100644 --- a/src/di/src/Container.php +++ b/src/di/src/Container.php @@ -114,7 +114,8 @@ class Container implements ContainerInterface * Returns false otherwise. * `has($name)` returning true does not mean that `get($name)` will not throw an exception. * It does however mean that `get($name)` will not throw a `NotFoundExceptionInterface`. - * @param mixed $name + * + * @param string $name Identifier of the entry to look for. */ public function has($name): bool { From ed4159bd8b60cfc4d4af111c99ddca3241edc4f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 13:34:09 +0800 Subject: [PATCH 127/225] Fixed typo. --- src/di/src/Aop/ProceedingJoinPoint.php | 2 +- src/di/src/Container.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/di/src/Aop/ProceedingJoinPoint.php b/src/di/src/Aop/ProceedingJoinPoint.php index a0a987abf..67d4ec45e 100644 --- a/src/di/src/Aop/ProceedingJoinPoint.php +++ b/src/di/src/Aop/ProceedingJoinPoint.php @@ -63,7 +63,7 @@ class ProceedingJoinPoint { $closure = $this->pipe; if (! $closure instanceof Closure) { - throw new Exception('The pipi is not instanceof \Closure'); + throw new Exception('The pipe is not instanceof \Closure'); } return $closure($this); diff --git a/src/di/src/Container.php b/src/di/src/Container.php index a6cace571..fe7998bce 100644 --- a/src/di/src/Container.php +++ b/src/di/src/Container.php @@ -115,7 +115,7 @@ class Container implements ContainerInterface * `has($name)` returning true does not mean that `get($name)` will not throw an exception. * It does however mean that `get($name)` will not throw a `NotFoundExceptionInterface`. * - * @param string $name Identifier of the entry to look for. + * @param string $name identifier of the entry to look for */ public function has($name): bool { From d0f97d0ac3f402218889b099221b05398b493004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 14:17:22 +0800 Subject: [PATCH 128/225] Update --- src/di/src/Collector/MetadataCollector.php | 76 ------------------- .../Collector/MetadataCollectorInterface.php | 44 ----------- src/di/src/ConfigProvider.php | 7 ++ .../MetadataCacheCollector.php | 44 ++++++----- src/di/src/MetadataCollectorInterface.php | 5 ++ src/di/tests/MetadataCollectorTest.php | 68 ++++++++++++++++- 6 files changed, 100 insertions(+), 144 deletions(-) delete mode 100644 src/di/src/Collector/MetadataCollector.php delete mode 100644 src/di/src/Collector/MetadataCollectorInterface.php rename src/di/src/{Collector => }/MetadataCacheCollector.php (51%) diff --git a/src/di/src/Collector/MetadataCollector.php b/src/di/src/Collector/MetadataCollector.php deleted file mode 100644 index 0be440e77..000000000 --- a/src/di/src/Collector/MetadataCollector.php +++ /dev/null @@ -1,76 +0,0 @@ -container = $container; - - $container->get(MetadataCacheCollector::class)->addCollector(static::class); - } - - /** - * Retrieve the metadata via key. - * @param null|mixed $default - */ - public function get(string $key, $default = null) - { - return Arr::get($this->metadata, $key) ?? $default; - } - - /** - * Set the metadata to holder. - * @param mixed $value - */ - public function set(string $key, $value): void - { - Arr::set($this->metadata, $key, $value); - } - - /** - * Determine if the metadata exist. - * If exist will return true, otherwise return false. - */ - public function has(string $key): bool - { - return Arr::has($this->metadata, $key); - } - - /** - * Get all metadata. - */ - public function getMetadata(): array - { - return $this->metadata; - } - - public function setMetadata(array $metadata): void - { - $this->metadata = $metadata; - } -} diff --git a/src/di/src/Collector/MetadataCollectorInterface.php b/src/di/src/Collector/MetadataCollectorInterface.php deleted file mode 100644 index 526f616b6..000000000 --- a/src/di/src/Collector/MetadataCollectorInterface.php +++ /dev/null @@ -1,44 +0,0 @@ - [ __DIR__, ], + 'cacheable' => [ + AnnotationCollector::class, + AspectCollector::class, + ], ], ]; } diff --git a/src/di/src/Collector/MetadataCacheCollector.php b/src/di/src/MetadataCacheCollector.php similarity index 51% rename from src/di/src/Collector/MetadataCacheCollector.php rename to src/di/src/MetadataCacheCollector.php index 8da55eab5..8fb6c933b 100644 --- a/src/di/src/Collector/MetadataCacheCollector.php +++ b/src/di/src/MetadataCacheCollector.php @@ -10,10 +10,9 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\Di\Collector; +namespace Hyperf\Di; -use Hyperf\Di\Exception\InvalidDefinitionException; -use Hyperf\Di\Exception\NotFoundException; +use Hyperf\Contract\ConfigInterface; use Psr\Container\ContainerInterface; class MetadataCacheCollector @@ -26,11 +25,16 @@ class MetadataCacheCollector /** * @var array */ - protected $collectors; + protected $collectors = []; public function __construct(ContainerInterface $container) { $this->container = $container; + + $collectors = $container->get(ConfigInterface::class)->get('scan.cacheable'); + foreach ($collectors as $collector) { + $this->addCollector($collector); + } } public function addCollector(string $collector) @@ -41,36 +45,34 @@ class MetadataCacheCollector )); } + public function clear() + { + $this->collectors = []; + } + public function serialize(): string { $metadata = []; foreach ($this->collectors as $collector) { - if ($this->container->has($collector)) { - $class = $this->container->get($collector); - if ($class instanceof MetadataCollectorInterface) { - $metadata[$collector] = $class->getMetadata(); - } + if (method_exists($collector, 'serialize')) { + $metadata[$collector] = call([$collector, 'serialize']); } } - return serialize($metadata); + return json_encode($metadata); } public function unserialize($serialized): void { - $metadatas = unserialize($serialized); - + $metadatas = json_decode($serialized, true); + $collectors = []; foreach ($metadatas as $collector => $metadata) { - if (! $this->container->has($collector)) { - throw new NotFoundException(sprintf('Collector %s not found in Container.')); + if (method_exists($collector, 'deserialize')) { + call([$collector, 'deserialize'], [$metadata]); + $collectors[] = $collector; } - - $class = $this->container->get($collector); - if (! $class instanceof MetadataCollectorInterface) { - throw new InvalidDefinitionException(sprintf('Collector %s is not instanceof MetadataCollectorInterface.')); - } - - $class->setMetadata($metadata); } + + $this->collectors = $collectors; } } diff --git a/src/di/src/MetadataCollectorInterface.php b/src/di/src/MetadataCollectorInterface.php index d86bbab0f..f1aef45f2 100644 --- a/src/di/src/MetadataCollectorInterface.php +++ b/src/di/src/MetadataCollectorInterface.php @@ -35,4 +35,9 @@ interface MetadataCollectorInterface * Deserialize the serialized metadata and set the metadata to holder. */ public static function deserialize(string $metadata): bool; + + /** + * Return all metadata array. + */ + public static function list(): array; } diff --git a/src/di/tests/MetadataCollectorTest.php b/src/di/tests/MetadataCollectorTest.php index a055ae750..f5c0ef02e 100644 --- a/src/di/tests/MetadataCollectorTest.php +++ b/src/di/tests/MetadataCollectorTest.php @@ -1,12 +1,74 @@ getContainer(); + $annotation = DemoAnnotation::class; + $id = uniqid(); + + AnnotationCollector::collectClass('Demo', $annotation, new DemoAnnotation($id)); + $collector = AnnotationCollector::list(); + + $cacher = new MetadataCacheCollector($container); + + $string = $cacher->serialize(); + AnnotationCollector::clear(); + $cacher->unserialize($string); + + $collector2 = AnnotationCollector::list(); + + $this->assertEquals($collector, $collector2); + } + + public function getContainer() + { + $container = Mockery::mock(ContainerInterface::class); + $container->shouldReceive('get')->with(ConfigInterface::class)->andReturn(new Config([ + 'scan' => [ + 'paths' => [ + __DIR__, + ], + 'cacheable' => [ + AnnotationCollector::class, + AspectCollector::class, + ], + ], + ])); + + return $container; + } +} From 28a9c9b2690d125a702ad7de894007bc8b265ab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 15:57:07 +0800 Subject: [PATCH 129/225] Added DefinitionSourceFactory. --- src/di/src/ConfigProvider.php | 3 +- src/di/src/Definition/DefinitionSource.php | 19 +++-- .../Definition/DefinitionSourceFactory.php | 71 +++++++++++++++++++ src/di/src/Definition/ScanConfig.php | 71 +++++++++++++++++++ src/di/src/MetadataCacheCollector.php | 17 +---- 5 files changed, 154 insertions(+), 27 deletions(-) create mode 100644 src/di/src/Definition/DefinitionSourceFactory.php create mode 100644 src/di/src/Definition/ScanConfig.php diff --git a/src/di/src/ConfigProvider.php b/src/di/src/ConfigProvider.php index 711e3bdc0..610b47cd8 100644 --- a/src/di/src/ConfigProvider.php +++ b/src/di/src/ConfigProvider.php @@ -14,7 +14,6 @@ namespace Hyperf\Di; use Hyperf\Di\Annotation\AnnotationCollector; use Hyperf\Di\Annotation\AspectCollector; -use Hyperf\Di\Aop\AstCollector; use Hyperf\Di\Command\InitProxyCommand; use Hyperf\Di\Listener\BootApplicationListener; @@ -36,7 +35,7 @@ class ConfigProvider 'paths' => [ __DIR__, ], - 'cacheable' => [ + 'collectors' => [ AnnotationCollector::class, AspectCollector::class, ], diff --git a/src/di/src/Definition/DefinitionSource.php b/src/di/src/Definition/DefinitionSource.php index b7daba97d..5fb9e9903 100644 --- a/src/di/src/Definition/DefinitionSource.php +++ b/src/di/src/Definition/DefinitionSource.php @@ -16,6 +16,7 @@ use Hyperf\Di\Annotation\AnnotationCollector; use Hyperf\Di\Annotation\AspectCollector; use Hyperf\Di\Annotation\Inject; use Hyperf\Di\Annotation\Scanner; +use Hyperf\Di\MetadataCacheCollector; use Hyperf\Di\ReflectionManager; use ReflectionClass; use ReflectionFunctionAbstract; @@ -67,13 +68,13 @@ class DefinitionSource implements DefinitionSourceInterface */ private $scanner; - public function __construct(array $source, array $scanDir, Scanner $scanner, bool $enableCache = false) + public function __construct(array $source, ScanConfig $scanConfig, bool $enableCache = false) { - $this->scanner = $scanner; + $this->scanner = new Scanner($scanConfig->getIgnoreAnnotations()); $this->enableCache = $enableCache; // Scan the specified paths and collect the ast and annotations. - $this->scan($scanDir); + $this->scan($scanConfig->getDirs(), $scanConfig->getCollectors()); $this->source = $this->normalizeSource($source); } @@ -214,18 +215,16 @@ class DefinitionSource implements DefinitionSourceInterface return $definition; } - private function scan(array $paths): bool + private function scan(array $paths, array $collectors): bool { if (empty($paths)) { return true; } $pathsHash = md5(implode(',', $paths)); + $cacher = new MetadataCacheCollector($collectors); if ($this->hasAvailableCache($paths, $pathsHash, $this->cachePath)) { $this->printLn('Detected an available cache, skip the scan process.'); - [, $annotationMetadata, $aspectMetadata] = explode(PHP_EOL, file_get_contents($this->cachePath)); - // Deserialize metadata when the cache is valid. - AnnotationCollector::deserialize($annotationMetadata); - AspectCollector::deserialize($aspectMetadata); + $cacher->unserialize(file_get_contents($this->cachePath)); return false; } $this->printLn('Scanning ...'); @@ -243,8 +242,8 @@ class DefinitionSource implements DefinitionSourceInterface mkdir($dirPath, 0755, true); } } - $data = implode(PHP_EOL, [$pathsHash, AnnotationCollector::serialize(), AspectCollector::serialize()]); - file_put_contents($this->cachePath, $data); + + file_put_contents($this->cachePath, $cacher->serialize()); return true; } diff --git a/src/di/src/Definition/DefinitionSourceFactory.php b/src/di/src/Definition/DefinitionSourceFactory.php new file mode 100644 index 000000000..190465a6f --- /dev/null +++ b/src/di/src/Definition/DefinitionSourceFactory.php @@ -0,0 +1,71 @@ +enableCache = $enableCache; + + if (! defined('BASE_PATH')) { + throw new Exception('BASE_PATH is not defined.'); + } + + $this->baseUri = BASE_PATH; + } + + public function __invoke() + { + $configDir = $this->baseUri . '/config'; + + $configFromProviders = []; + if (class_exists(ProviderConfig::class)) { + $configFromProviders = ProviderConfig::load(); + } + + $serverDependencies = $configFromProviders['dependencies'] ?? []; + if (file_exists($configDir . '/dependencies.php')) { + $definitions = include $configDir . '/dependencies.php'; + $serverDependencies = array_replace($serverDependencies, $definitions['dependencies'] ?? []); + } + + $scanDirs = $configFromProviders['scan']['paths'] ?? []; + $ignoreAnnotations = []; + $collectors = $configFromProviders['scan']['collectors'] ?? []; + + if (file_exists($configDir . '/autoload/annotations.php')) { + $annotations = include $configDir . '/autoload/annotations.php'; + $scanDirs = array_merge($scanDirs, $annotations['scan']['paths'] ?? []); + $ignoreAnnotations = $annotations['scan']['ignore_annotations'] ?? []; + $collectors = array_merge($collectors, $annotations['scan']['collectors'] ?? []); + } + + $scanConfig = new ScanConfig($scanDirs, $ignoreAnnotations, $collectors); + + return new DefinitionSource($serverDependencies, $scanConfig, $this->enableCache); + } +} diff --git a/src/di/src/Definition/ScanConfig.php b/src/di/src/Definition/ScanConfig.php new file mode 100644 index 000000000..385fe2b6e --- /dev/null +++ b/src/di/src/Definition/ScanConfig.php @@ -0,0 +1,71 @@ +dirs = $dirs; + $this->ignoreAnnotations = $ignoreAnnotations; + $this->collectors = $collectors; + } + + public function getDirs(): array + { + return $this->dirs; + } + + public function setDirs(array $dirs): self + { + $this->dirs = $dirs; + return $this; + } + + public function getIgnoreAnnotations(): array + { + return $this->ignoreAnnotations; + } + + public function setIgnoreAnnotations(array $ignoreAnnotations): self + { + $this->ignoreAnnotations = $ignoreAnnotations; + return $this; + } + + public function getCollectors(): array + { + return $this->collectors; + } + + public function setCollectors(array $collectors): self + { + $this->collectors = $collectors; + return $this; + } +} diff --git a/src/di/src/MetadataCacheCollector.php b/src/di/src/MetadataCacheCollector.php index 8fb6c933b..9d74b7efd 100644 --- a/src/di/src/MetadataCacheCollector.php +++ b/src/di/src/MetadataCacheCollector.php @@ -12,29 +12,16 @@ declare(strict_types=1); namespace Hyperf\Di; -use Hyperf\Contract\ConfigInterface; -use Psr\Container\ContainerInterface; - class MetadataCacheCollector { - /** - * @var ContainerInterface - */ - protected $container; - /** * @var array */ protected $collectors = []; - public function __construct(ContainerInterface $container) + public function __construct(array $collectors) { - $this->container = $container; - - $collectors = $container->get(ConfigInterface::class)->get('scan.cacheable'); - foreach ($collectors as $collector) { - $this->addCollector($collector); - } + $this->collectors = $collectors; } public function addCollector(string $collector) From 7ceb01400371568a0a953f9d0b3fd68e39545705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 15:59:14 +0800 Subject: [PATCH 130/225] Fixed testing. --- src/di/src/Definition/ScanConfig.php | 2 +- src/di/tests/ContainerTest.php | 4 ++-- src/di/tests/DefinitionSourceTest.php | 4 ++-- src/di/tests/MakeTest.php | 4 ++-- src/di/tests/MetadataCollectorTest.php | 6 ++++-- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/di/src/Definition/ScanConfig.php b/src/di/src/Definition/ScanConfig.php index 385fe2b6e..1b95d789d 100644 --- a/src/di/src/Definition/ScanConfig.php +++ b/src/di/src/Definition/ScanConfig.php @@ -29,7 +29,7 @@ class ScanConfig */ protected $collectors; - public function __construct(array $dirs, array $ignoreAnnotations, array $collectors) + public function __construct(array $dirs = [], array $ignoreAnnotations = [], array $collectors = []) { $this->dirs = $dirs; $this->ignoreAnnotations = $ignoreAnnotations; diff --git a/src/di/tests/ContainerTest.php b/src/di/tests/ContainerTest.php index d2fc9de40..c342e80c5 100644 --- a/src/di/tests/ContainerTest.php +++ b/src/di/tests/ContainerTest.php @@ -12,9 +12,9 @@ declare(strict_types=1); namespace HyperfTest\Di; -use Hyperf\Di\Annotation\Scanner; use Hyperf\Di\Container; use Hyperf\Di\Definition\DefinitionSource; +use Hyperf\Di\Definition\ScanConfig; use HyperfTest\Di\Stub\Foo; use HyperfTest\Di\Stub\FooInterface; use PHPUnit\Framework\TestCase; @@ -27,7 +27,7 @@ class ContainerTest extends TestCase { public function testHas() { - $container = new Container(new DefinitionSource([], [], new Scanner())); + $container = new Container(new DefinitionSource([], new ScanConfig())); $this->assertFalse($container->has(FooInterface::class)); $this->assertFalse($container->has(NotExistClass::class)); $this->assertTrue($container->has(Foo::class)); diff --git a/src/di/tests/DefinitionSourceTest.php b/src/di/tests/DefinitionSourceTest.php index 6630ca941..579dbc1dc 100644 --- a/src/di/tests/DefinitionSourceTest.php +++ b/src/di/tests/DefinitionSourceTest.php @@ -12,9 +12,9 @@ declare(strict_types=1); namespace HyperfTest\Di; -use Hyperf\Di\Annotation\Scanner; use Hyperf\Di\Container; use Hyperf\Di\Definition\DefinitionSource; +use Hyperf\Di\Definition\ScanConfig; use PHPUnit\Framework\TestCase; /** @@ -25,7 +25,7 @@ class DefinitionSourceTest extends TestCase { public function testAddDefinition() { - $container = new Container(new DefinitionSource([], [], new Scanner())); + $container = new Container(new DefinitionSource([], new ScanConfig())); $container->getDefinitionSource()->addDefinition('Foo', function () { return 'bar'; }); diff --git a/src/di/tests/MakeTest.php b/src/di/tests/MakeTest.php index 3138b998c..fb9b372fd 100644 --- a/src/di/tests/MakeTest.php +++ b/src/di/tests/MakeTest.php @@ -12,9 +12,9 @@ declare(strict_types=1); namespace HyperfTest\Di; -use Hyperf\Di\Annotation\Scanner; use Hyperf\Di\Container; use Hyperf\Di\Definition\DefinitionSource; +use Hyperf\Di\Definition\ScanConfig; use Hyperf\Utils\ApplicationContext; use HyperfTest\Di\Stub\Bar; use HyperfTest\Di\Stub\Demo; @@ -29,7 +29,7 @@ class MakeTest extends TestCase { public function setUp() { - $container = new Container(new DefinitionSource([], [], new Scanner())); + $container = new Container(new DefinitionSource([], new ScanConfig())); ApplicationContext::setContainer($container); } diff --git a/src/di/tests/MetadataCollectorTest.php b/src/di/tests/MetadataCollectorTest.php index f5c0ef02e..3f57e6f71 100644 --- a/src/di/tests/MetadataCollectorTest.php +++ b/src/di/tests/MetadataCollectorTest.php @@ -36,14 +36,16 @@ class MetadataCollectorTest extends TestCase public function testMetadataCollectorCache() { - $container = $this->getContainer(); $annotation = DemoAnnotation::class; $id = uniqid(); AnnotationCollector::collectClass('Demo', $annotation, new DemoAnnotation($id)); $collector = AnnotationCollector::list(); - $cacher = new MetadataCacheCollector($container); + $cacher = new MetadataCacheCollector([ + AnnotationCollector::class, + AspectCollector::class, + ]); $string = $cacher->serialize(); AnnotationCollector::clear(); From 883e155ee5c26cc049d65c48c3ee82b61d045f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 16:12:07 +0800 Subject: [PATCH 131/225] Added ConstantsCollector into Cacher. --- src/constants/composer.json | 1 + src/constants/src/ConfigProvider.php | 30 ++++++++++++++++++++++ src/constants/src/ConstantsCollector.php | 6 ++--- src/di/src/Definition/DefinitionSource.php | 6 +++-- 4 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 src/constants/src/ConfigProvider.php diff --git a/src/constants/composer.json b/src/constants/composer.json index 37d49195d..befd26d45 100644 --- a/src/constants/composer.json +++ b/src/constants/composer.json @@ -40,6 +40,7 @@ "dev-master": "1.1-dev" }, "hyperf": { + "config": "Hyperf\\Constants\\ConfigProvider" } }, "bin": [ diff --git a/src/constants/src/ConfigProvider.php b/src/constants/src/ConfigProvider.php new file mode 100644 index 000000000..420568eac --- /dev/null +++ b/src/constants/src/ConfigProvider.php @@ -0,0 +1,30 @@ + [ + ], + 'scan' => [ + 'paths' => [], + 'collectors' => [ + ConstantsCollector::class, + ], + ], + ]; + } +} diff --git a/src/constants/src/ConstantsCollector.php b/src/constants/src/ConstantsCollector.php index 77f330134..351b77596 100644 --- a/src/constants/src/ConstantsCollector.php +++ b/src/constants/src/ConstantsCollector.php @@ -12,12 +12,10 @@ declare(strict_types=1); namespace Hyperf\Constants; -use Hyperf\Utils\Traits\Container; +use Hyperf\Di\MetadataCollector; -class ConstantsCollector +class ConstantsCollector extends MetadataCollector { - use Container; - /** * @var array */ diff --git a/src/di/src/Definition/DefinitionSource.php b/src/di/src/Definition/DefinitionSource.php index 5fb9e9903..53be055d2 100644 --- a/src/di/src/Definition/DefinitionSource.php +++ b/src/di/src/Definition/DefinitionSource.php @@ -224,7 +224,8 @@ class DefinitionSource implements DefinitionSourceInterface $cacher = new MetadataCacheCollector($collectors); if ($this->hasAvailableCache($paths, $pathsHash, $this->cachePath)) { $this->printLn('Detected an available cache, skip the scan process.'); - $cacher->unserialize(file_get_contents($this->cachePath)); + [, $serialized] = explode(PHP_EOL, file_get_contents($this->cachePath)); + $cacher->unserialize($serialized); return false; } $this->printLn('Scanning ...'); @@ -243,7 +244,8 @@ class DefinitionSource implements DefinitionSourceInterface } } - file_put_contents($this->cachePath, $cacher->serialize()); + $data = implode(PHP_EOL, [$pathsHash, $cacher->serialize()]); + file_put_contents($this->cachePath, $data); return true; } From cd36f779733eb53f73b507d458b7644f13b94449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 16:14:51 +0800 Subject: [PATCH 132/225] Added CacheListenerCollector into Cacher. --- src/cache/src/CacheListenerCollector.php | 5 ++--- src/cache/src/ConfigProvider.php | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cache/src/CacheListenerCollector.php b/src/cache/src/CacheListenerCollector.php index 0444ae171..2bacc297d 100644 --- a/src/cache/src/CacheListenerCollector.php +++ b/src/cache/src/CacheListenerCollector.php @@ -12,12 +12,11 @@ declare(strict_types=1); namespace Hyperf\Cache; +use Hyperf\Di\MetadataCollector; use Hyperf\Utils\Traits\Container; -class CacheListenerCollector +class CacheListenerCollector extends MetadataCollector { - use Container; - /** * @var array */ diff --git a/src/cache/src/ConfigProvider.php b/src/cache/src/ConfigProvider.php index 689c4ad2f..fe493acbf 100644 --- a/src/cache/src/ConfigProvider.php +++ b/src/cache/src/ConfigProvider.php @@ -28,6 +28,9 @@ class ConfigProvider 'paths' => [ __DIR__, ], + 'collectors' => [ + CacheListenerCollector::class, + ] ], 'publish' => [ [ From d739e67c02f4224c255d53b5abc7b05a622a7295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 16:23:59 +0800 Subject: [PATCH 133/225] Fixed testing. --- src/di/src/MetadataCacheCollector.php | 2 +- src/json-rpc/tests/RpcServiceClientTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/di/src/MetadataCacheCollector.php b/src/di/src/MetadataCacheCollector.php index 9d74b7efd..9cc8d0608 100644 --- a/src/di/src/MetadataCacheCollector.php +++ b/src/di/src/MetadataCacheCollector.php @@ -51,7 +51,7 @@ class MetadataCacheCollector public function unserialize($serialized): void { - $metadatas = json_decode($serialized, true); + $metadatas = json_decode($serialized, true) ?? []; $collectors = []; foreach ($metadatas as $collector => $metadata) { if (method_exists($collector, 'deserialize')) { diff --git a/src/json-rpc/tests/RpcServiceClientTest.php b/src/json-rpc/tests/RpcServiceClientTest.php index 34029dd5a..69c5a2563 100644 --- a/src/json-rpc/tests/RpcServiceClientTest.php +++ b/src/json-rpc/tests/RpcServiceClientTest.php @@ -16,9 +16,9 @@ use Hyperf\Config\Config; use Hyperf\Contract\ConfigInterface; use Hyperf\Contract\NormalizerInterface; use Hyperf\Contract\StdoutLoggerInterface; -use Hyperf\Di\Annotation\Scanner; use Hyperf\Di\Container; use Hyperf\Di\Definition\DefinitionSource; +use Hyperf\Di\Definition\ScanConfig; use Hyperf\Di\MethodDefinitionCollector; use Hyperf\Di\MethodDefinitionCollectorInterface; use Hyperf\JsonRpc\DataFormatter; @@ -142,7 +142,7 @@ class RpcServiceClientTest extends TestCase JsonRpcTransporter::class => function () use ($transporter) { return $transporter; }, - ], [], new Scanner())); + ], new ScanConfig())); ApplicationContext::setContainer($container); return $container; } From db46096c7610a32ca3b68f988fb72136cb9b2f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 16:37:40 +0800 Subject: [PATCH 134/225] Added ListenerCollector into cacher. --- .../src/Collector/ListenerCollector.php | 16 +++++++++------- src/model-listener/tests/AnnotationTest.php | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/model-listener/src/Collector/ListenerCollector.php b/src/model-listener/src/Collector/ListenerCollector.php index f93dca340..73d035cda 100644 --- a/src/model-listener/src/Collector/ListenerCollector.php +++ b/src/model-listener/src/Collector/ListenerCollector.php @@ -12,7 +12,9 @@ declare(strict_types=1); namespace Hyperf\ModelListener\Collector; -class ListenerCollector +use Hyperf\Di\MetadataCollector; + +class ListenerCollector extends MetadataCollector { /** * User exposed listeners. @@ -21,16 +23,16 @@ class ListenerCollector * * @var array */ - protected static $listeners = []; + protected static $container = []; /** * Register a single listener with the model. */ public static function register(string $model, string $listener): void { - static::$listeners[$model] = array_unique( + static::$container[$model] = array_unique( array_merge( - static::$listeners[$model] ?? [], + static::$container[$model] ?? [], [$listener] ) ); @@ -38,12 +40,12 @@ class ListenerCollector public static function setListenersForModel(string $model, array $listeners): void { - static::$listeners[$model] = $listeners; + static::$container[$model] = $listeners; } public static function getListenersForModel(string $model): array { - return static::$listeners[$model] ?? []; + return static::$container[$model] ?? []; } /** @@ -51,6 +53,6 @@ class ListenerCollector */ public static function clearListeners(): void { - static::$listeners = []; + static::$container = []; } } diff --git a/src/model-listener/tests/AnnotationTest.php b/src/model-listener/tests/AnnotationTest.php index 1f08164f2..f3f3c59f3 100644 --- a/src/model-listener/tests/AnnotationTest.php +++ b/src/model-listener/tests/AnnotationTest.php @@ -12,8 +12,8 @@ declare(strict_types=1); namespace HyperfTest\ModelListener; -use Hyperf\ModelListener\Collector\ListenerCollector; use Hyperf\ModelListener\Annotation\ModelListener; +use Hyperf\ModelListener\Collector\ListenerCollector; use HyperfTest\ModelListener\Stub\ModelStub; use PHPUnit\Framework\TestCase; From 27676f2708ca188a41397c9bdce003cc9d6709f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 27 Aug 2019 16:50:51 +0800 Subject: [PATCH 135/225] Update --- src/di/src/Command/InitProxyCommand.php | 2 +- src/model-listener/src/ConfigProvider.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/di/src/Command/InitProxyCommand.php b/src/di/src/Command/InitProxyCommand.php index 8e3c08f59..22adb3157 100644 --- a/src/di/src/Command/InitProxyCommand.php +++ b/src/di/src/Command/InitProxyCommand.php @@ -57,7 +57,7 @@ class InitProxyCommand extends Command protected function clearRuntime($paths) { $finder = new Finder(); - $finder->files()->in($paths)->name('*.php'); + $finder->files()->in($paths)->name(['*.php', '*.cache']); /** @var SplFileInfo $file */ foreach ($finder as $file) { diff --git a/src/model-listener/src/ConfigProvider.php b/src/model-listener/src/ConfigProvider.php index 91c08c8c8..ca078b9d0 100644 --- a/src/model-listener/src/ConfigProvider.php +++ b/src/model-listener/src/ConfigProvider.php @@ -12,6 +12,8 @@ declare(strict_types=1); namespace Hyperf\ModelListener; +use Hyperf\ModelListener\Collector\ListenerCollector; + class ConfigProvider { public function __invoke(): array @@ -25,6 +27,9 @@ class ConfigProvider 'paths' => [ __DIR__, ], + 'collectors' => [ + ListenerCollector::class, + ], ], ]; } From 76e3fc08c753b59299dcf5d97af3e4ca301db732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Tue, 27 Aug 2019 16:54:42 +0800 Subject: [PATCH 136/225] Fix typo --- src/di/tests/AstTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/di/tests/AstTest.php b/src/di/tests/AstTest.php index 349344cca..20a08c4f1 100644 --- a/src/di/tests/AstTest.php +++ b/src/di/tests/AstTest.php @@ -29,7 +29,7 @@ class AstTest extends TestCase public function testProxy() { $ast = new Ast(); - $proxyClass = Foo::class . 'Froxy'; + $proxyClass = Foo::class . 'Proxy'; $code = $ast->proxy(Foo::class, $proxyClass); $this->assertEquals('proxy(Bar2::class, $proxyClass); $this->assertEquals('proxy(Bar3::class, $proxyClass); $this->assertEquals(' Date: Tue, 27 Aug 2019 16:57:46 +0800 Subject: [PATCH 137/225] Update CHANGELOG.md --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b452c640..121c001a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,24 @@ ## Changed - [#437](https://github.com/hyperf-cloud/hyperf/pull/437) Changed `Hyperf\Testing\Client` handle exception handlers instead of throw an exception directly. +- [#463](https://github.com/hyperf-cloud/hyperf/pull/463) Simplify `container.php` and improve annotation caching mechanism. + +config/container.php + +```php + Date: Tue, 27 Aug 2019 19:38:23 +0800 Subject: [PATCH 138/225] Update MetadataCacheCollector.php --- src/di/src/MetadataCacheCollector.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/di/src/MetadataCacheCollector.php b/src/di/src/MetadataCacheCollector.php index 9cc8d0608..b242a6c9b 100644 --- a/src/di/src/MetadataCacheCollector.php +++ b/src/di/src/MetadataCacheCollector.php @@ -40,6 +40,7 @@ class MetadataCacheCollector public function serialize(): string { $metadata = []; + /** @var string $collector */ foreach ($this->collectors as $collector) { if (method_exists($collector, 'serialize')) { $metadata[$collector] = call([$collector, 'serialize']); From 85484a4dd86b7903ff6459f169cee951fb0cee0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 28 Aug 2019 09:29:00 +0800 Subject: [PATCH 139/225] Update MetadataCacheCollector.php --- src/di/src/MetadataCacheCollector.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/di/src/MetadataCacheCollector.php b/src/di/src/MetadataCacheCollector.php index b242a6c9b..f7aff7992 100644 --- a/src/di/src/MetadataCacheCollector.php +++ b/src/di/src/MetadataCacheCollector.php @@ -40,9 +40,8 @@ class MetadataCacheCollector public function serialize(): string { $metadata = []; - /** @var string $collector */ foreach ($this->collectors as $collector) { - if (method_exists($collector, 'serialize')) { + if (is_string($collector) && method_exists($collector, 'serialize')) { $metadata[$collector] = call([$collector, 'serialize']); } } From cb4ead1cc89d4dc962008dbe8147e65abd0b6054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=9F=8E=E9=93=AD?= <767036228@qq.com> Date: Wed, 28 Aug 2019 11:42:06 +0800 Subject: [PATCH 140/225] Update rate-limit.md --- doc/zh/rate-limit.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/zh/rate-limit.md b/doc/zh/rate-limit.md index abce56c33..3584dd133 100644 --- a/doc/zh/rate-limit.md +++ b/doc/zh/rate-limit.md @@ -86,7 +86,7 @@ use Hyperf\RateLimit\Annotation\RateLimit; /** * @Controller(prefix="rate-limit") - * @RateLimit(limitCallback={RateLimitController::class, 'limitCallback'}) + * @RateLimit(limitCallback={RateLimitController::class, "limitCallback"}) */ class RateLimitController { @@ -107,4 +107,4 @@ class RateLimitController return $proceedingJoinPoint->process(); } } -``` \ No newline at end of file +``` From 3255a0fd1e4b31702cab0efb80eb823c2c57938c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 28 Aug 2019 11:42:27 +0800 Subject: [PATCH 141/225] Format code. --- .../src/Exception/Handler/HttpExceptionHandler.php | 1 - src/http-server/src/Router/DispatcherFactory.php | 2 +- src/http-server/tests/Stub/DemoController.php | 10 +++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/http-server/src/Exception/Handler/HttpExceptionHandler.php b/src/http-server/src/Exception/Handler/HttpExceptionHandler.php index ae171adf9..9f55db5df 100644 --- a/src/http-server/src/Exception/Handler/HttpExceptionHandler.php +++ b/src/http-server/src/Exception/Handler/HttpExceptionHandler.php @@ -16,7 +16,6 @@ use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\ExceptionHandler\ExceptionHandler; use Hyperf\ExceptionHandler\Formatter\FormatterInterface; use Hyperf\HttpMessage\Stream\SwooleStream; -use Hyperf\Server\Exception\ServerException; use Psr\Http\Message\ResponseInterface; use Throwable; diff --git a/src/http-server/src/Router/DispatcherFactory.php b/src/http-server/src/Router/DispatcherFactory.php index b76fe7545..fa6825f03 100644 --- a/src/http-server/src/Router/DispatcherFactory.php +++ b/src/http-server/src/Router/DispatcherFactory.php @@ -120,7 +120,7 @@ class DispatcherFactory if (substr($methodName, 0, 2) === '__') { continue; } - + $router->addRoute($autoMethods, $path, [$className, $methodName, $annotation->server]); $methodMiddlewares = $middlewares; diff --git a/src/http-server/tests/Stub/DemoController.php b/src/http-server/tests/Stub/DemoController.php index 9561eae5e..2219d8b33 100644 --- a/src/http-server/tests/Stub/DemoController.php +++ b/src/http-server/tests/Stub/DemoController.php @@ -18,13 +18,13 @@ class DemoController { } - public function index(int $id, string $name = 'Hyperf', array $params = []) - { - return $this->__return($id, $name, $params); - } - public function __return(...$args) { return $args; } + + public function index(int $id, string $name = 'Hyperf', array $params = []) + { + return $this->__return($id, $name, $params); + } } From 235354bd87fde5535505b5afcad7fe1ba0110890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 28 Aug 2019 11:45:14 +0800 Subject: [PATCH 142/225] Fixed hyperf components version. --- src/config-etcd/composer.json | 1 - src/etcd/composer.json | 1 - src/translation/composer.json | 5 ++--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/config-etcd/composer.json b/src/config-etcd/composer.json index 1d6b4ce16..66c454af4 100644 --- a/src/config-etcd/composer.json +++ b/src/config-etcd/composer.json @@ -27,7 +27,6 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", - "hyperf/testing": "1.0.*", "phpstan/phpstan": "^0.10.5", "swoft/swoole-ide-helper": "dev-master" }, diff --git a/src/etcd/composer.json b/src/etcd/composer.json index 4c7c88f87..ed4b66312 100644 --- a/src/etcd/composer.json +++ b/src/etcd/composer.json @@ -25,7 +25,6 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", - "hyperf/testing": "1.0.*", "phpstan/phpstan": "^0.10.5", "swoft/swoole-ide-helper": "dev-master" }, diff --git a/src/translation/composer.json b/src/translation/composer.json index 0527ee253..9b21b8bfa 100644 --- a/src/translation/composer.json +++ b/src/translation/composer.json @@ -22,13 +22,12 @@ }, "require": { "php": ">=7.2", - "hyperf/contract": "1.0.*", - "hyperf/utils": "1.0.*", + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0", "psr/container": "^1.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", - "hyperf/testing": "1.0.*", "mockery/mockery": "^1.2", "phpstan/phpstan": "^0.10.5" }, From 1a425b1068742e02de0b8171c78b20205958260b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 28 Aug 2019 11:54:16 +0800 Subject: [PATCH 143/225] Fixed bug. --- src/http-server/src/Router/DispatcherFactory.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/http-server/src/Router/DispatcherFactory.php b/src/http-server/src/Router/DispatcherFactory.php index fa6825f03..fea36cd17 100644 --- a/src/http-server/src/Router/DispatcherFactory.php +++ b/src/http-server/src/Router/DispatcherFactory.php @@ -121,8 +121,6 @@ class DispatcherFactory continue; } - $router->addRoute($autoMethods, $path, [$className, $methodName, $annotation->server]); - $methodMiddlewares = $middlewares; // Handle method level middlewares. if (isset($methodMetadata[$methodName])) { From bad25a44f5096fff8ac0025f53abd0456795dc08 Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Wed, 28 Aug 2019 18:25:34 +0800 Subject: [PATCH 144/225] Update awesome-components.md --- doc/zh/awesome-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/awesome-components.md b/doc/zh/awesome-components.md index 34ae84326..3050f3a40 100644 --- a/doc/zh/awesome-components.md +++ b/doc/zh/awesome-components.md @@ -106,7 +106,7 @@ ## Swoole -- - [hyperf/swoole-enterprise](https://github.com/hyperf-cloud/swoole-enterprise) Hyperf 官方提供的对接 Swoole Enterprise (Swoole Tracker) 的组件,提供阻塞分析、性能分析、内存泄漏分析、运行状态及调用统计等功能 +- - [hyperf/swoole-tracker](https://github.com/hyperf-cloud/swoole-tracker) Hyperf 官方提供的对接 Swoole Tracker 的组件,提供阻塞分析、性能分析、内存泄漏分析、运行状态及调用统计等功能 - - [hyperf/task](https://github.com/hyperf-cloud/task) Hyperf 官方提供的 Task 组件,对 Swoole 的 Task 机制进行了封装及抽象,提供便捷的注解用法 > Warning: 请勿于生产环境使用 `热更新/热重载` 功能 From 30b6ee60bfa12082fca47e611c30158beb4dcf35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Wed, 28 Aug 2019 18:34:39 +0800 Subject: [PATCH 145/225] Update logger.md --- doc/zh/logger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/logger.md b/doc/zh/logger.md index a48764802..7e1ad4269 100644 --- a/doc/zh/logger.md +++ b/doc/zh/logger.md @@ -1,6 +1,6 @@ # 日志 -`hyperf/logger` 组件是基于 [psr/logger](https://github.com/php-fig/logger) 实现的,默认使用 [monolog/monolog](https://github.com/Seldaek/monolog) 作为驱动,在 `hyperf-skeleton` 项目内默认提供了一些日志配置,默认使用 `Monolog\Handler\StreamHandler`, 由于 `Swoole` 已经对 `fopen`, `fwrite` 等函数进行了协程化处理,所以只要不将 `useLocking` 参数设置为 `true`,就是协程安全的。 +`hyperf/logger` 组件是基于 [psr/logger](https://github.com/php-fig/log) 实现的,默认使用 [monolog/monolog](https://github.com/Seldaek/monolog) 作为驱动,在 `hyperf-skeleton` 项目内默认提供了一些日志配置,默认使用 `Monolog\Handler\StreamHandler`, 由于 `Swoole` 已经对 `fopen`, `fwrite` 等函数进行了协程化处理,所以只要不将 `useLocking` 参数设置为 `true`,就是协程安全的。 ## 安装 From 0859e043198d65e075ee3480236f8383734da304 Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Wed, 28 Aug 2019 18:50:41 +0800 Subject: [PATCH 146/225] Update and rename swoole-enterprise.md to swoole-tracker.md --- ...{swoole-enterprise.md => swoole-tracker.md} | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) rename doc/zh/{swoole-enterprise.md => swoole-tracker.md} (83%) diff --git a/doc/zh/swoole-enterprise.md b/doc/zh/swoole-tracker.md similarity index 83% rename from doc/zh/swoole-enterprise.md rename to doc/zh/swoole-tracker.md index 603780a81..0427e830b 100644 --- a/doc/zh/swoole-enterprise.md +++ b/doc/zh/swoole-tracker.md @@ -1,6 +1,6 @@ -# Swoole Enterprise +# Swoole Tracker -[Swoole Enterprise](https://www.swoole-cloud.com/dashboard.html) 作为 `Swoole` 官方出品的一整套企业级`PHP`和`Swoole`分析调试工具,更专一、更专业。 +[Swoole Tracker](https://www.swoole-cloud.com/tracker.html) 作为 `Swoole` 官方出品的一整套企业级`PHP`和`Swoole`分析调试工具,更专一、更专业。 - 时刻掌握应用架构模型 > 自动发现应用依赖拓扑结构和展示,时刻掌握应用的架构模型 @@ -21,7 +21,7 @@ 注册完账户后,进入[控制台](https://www.swoole-cloud.com/dashboard/catdemo/),并申请试用,下载对应客户端。 -相关文档,请移步 [试用文档](https://www.yuque.com/swoole-wiki/try) 或 [详细文档](https://www.yuque.com/swoole-wiki/dam5n7) +相关文档,请移步 [试用文档](https://www.kancloud.cn/swoole-inc/ee-base-wiki/1214079) 或 [详细文档](https://www.kancloud.cn/swoole-inc/ee-help-wiki/1213080) > 具体文档地址,以从控制台下载的对应客户端中展示的为准。 @@ -38,11 +38,11 @@ php /opt/www/bin/hyperf.php start ``` -2. `swoole-plus.ini` +2. `swoole-tracker.ini` ```bash [swoole_plus] -extension=/opt/swoole_plus.so +extension=/opt/swoole_tracker.so apm.enable=1 #打开总开关 apm.sampling_rate=100 #采样率 例如:100% @@ -98,8 +98,8 @@ WORKDIR /opt/www/.build # 这里的地址,以客户端中显示的为准 RUN ./deploy_env.sh www.swoole-cloud.com \ && chmod 755 entrypoint.sh \ - && cp swoole_plus72.so /opt/swoole_plus.so \ - && cp swoole-plus.ini /etc/php7/conf.d/swoole-plus.ini \ + && cp swoole_tracker72.so /opt/swoole_tracker.so \ + && cp swoole-tracker.ini /etc/php7/conf.d/swoole-tracker.ini \ && php -m WORKDIR /opt/www @@ -121,14 +121,14 @@ composer require hyperf/swoole-enterprise ## 使用 -在 `config/autoload/middlewares.php` 配置文件中注册 `Hyperf\SwooleEnterprise\Middleware\HttpServerMiddleware` 中间件即可,如下: +在 `config/autoload/middlewares.php` 配置文件中注册 `Hyperf\SwooleTracker\Middleware\HttpServerMiddleware` 中间件即可,如下: ```php [ - Hyperf\SwooleEnterprise\Middleware\HttpServerMiddleware::class + Hyperf\SwooleTracker\Middleware\HttpServerMiddleware::class ], ]; ``` From 4d14fb5981aedd9f9a1848b92c978bbfa935ea21 Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Wed, 28 Aug 2019 18:51:52 +0800 Subject: [PATCH 147/225] Update swoole-tracker.md --- doc/zh/swoole-tracker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/swoole-tracker.md b/doc/zh/swoole-tracker.md index 0427e830b..4a94bb595 100644 --- a/doc/zh/swoole-tracker.md +++ b/doc/zh/swoole-tracker.md @@ -116,7 +116,7 @@ ENTRYPOINT ["sh", ".build/entrypoint.sh"] ### 安装组件 ```bash -composer require hyperf/swoole-enterprise +composer require hyperf/swoole-tracker ``` ## 使用 From 41e53dacaa77887378aacd0ac272522579f8378e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Wed, 28 Aug 2019 19:05:43 +0800 Subject: [PATCH 148/225] Update summary.md --- doc/zh/summary.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/zh/summary.md b/doc/zh/summary.md index e7ef8cc55..fa0e87158 100644 --- a/doc/zh/summary.md +++ b/doc/zh/summary.md @@ -35,6 +35,7 @@ * [命令行](zh/command.md) * [自动化测试](zh/testing.md) * [视图](zh/view.md) + * [国际化](zh/translation.md) * 数据库模型 From 21f09cf2bd1e06c19d37516c436e770eb3051e6f Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 28 Aug 2019 19:49:39 +0800 Subject: [PATCH 149/225] optimize sendfile merge to send --- doc/zh/response.md | 5 +- src/http-message/src/Server/Response.php | 32 +-- .../src/Stream/SwooleFileStream.php | 233 ++++++++++++++++++ .../src/Contract/ResponseInterface.php | 8 + src/http-server/src/Response.php | 34 +++ 5 files changed, 284 insertions(+), 28 deletions(-) create mode 100644 src/http-message/src/Stream/SwooleFileStream.php diff --git a/doc/zh/response.md b/doc/zh/response.md index c80664ba1..0973b54da 100644 --- a/doc/zh/response.md +++ b/doc/zh/response.md @@ -135,9 +135,10 @@ use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface; class IndexController { - public function download(Response $response): Psr7ResponseInterface + public function download(ResponseInterface $response): Psr7ResponseInterface { - return $response->sendfile('/var/www/file.csv'); + // redirect() 方法返回的是一个 Psr\Http\Message\ResponseInterface 对象,需再 return 回去 + return $response->download('/var/www/file.csv','filename.csv'); } } ``` \ No newline at end of file diff --git a/src/http-message/src/Server/Response.php b/src/http-message/src/Server/Response.php index dde95b4ca..d3b928276 100755 --- a/src/http-message/src/Server/Response.php +++ b/src/http-message/src/Server/Response.php @@ -14,6 +14,7 @@ namespace Hyperf\HttpMessage\Server; use Hyperf\HttpMessage\Cookie\Cookie; use Hyperf\HttpMessage\Stream\SwooleStream; +use Hyperf\HttpMessage\Stream\SwooleFileStream; class Response extends \Hyperf\HttpMessage\Base\Response { @@ -35,42 +36,21 @@ class Response extends \Hyperf\HttpMessage\Base\Response $this->swooleResponse = $response; } - /** - * @var bool - */ - protected $isEnd = false; - /** * Handle response and send. */ public function send() { - if ($this->isEnd || !$this->getSwooleResponse()) { + if (! $this->getSwooleResponse()) { return; } $this->buildSwooleResponse($this->swooleResponse, $this); - - $this->swooleResponse->end($this->getBody()->getContents()); - } - - /** - * Handle response and sendfile. - * @param string $file_name - * @param string $content_type - */ - public function sendfile(string $file_name, string $content_type = 'application/octet-stream') - { - $response = $this->getSwooleResponse(); - $response->setStatusCode(200); - $response->setHeader('Content-Description', 'File Transfer'); - $response->setHeader('Content-Type', $content_type); - $response->setHeader('Content-Disposition', 'attachment; filename=' . basename($file_name)); - $response->setHeader('Content-Transfer-Encoding', 'binary'); - $response->setHeader('Pragma', 'public'); - if ($response->sendfile($file_name)) { - $this->isEnd = true; + $content = $this->getBody(); + if($content instanceof SwooleFileStream){ + return $this->swooleResponse->sendfile($content->getContents()); } + $this->swooleResponse->end($content->getContents()); } /** diff --git a/src/http-message/src/Stream/SwooleFileStream.php b/src/http-message/src/Stream/SwooleFileStream.php new file mode 100644 index 000000000..d18e56247 --- /dev/null +++ b/src/http-message/src/Stream/SwooleFileStream.php @@ -0,0 +1,233 @@ +contents = $file_path; + $this->size = filesize($file_path); + } + + /** + * Reads all data from the stream into a string, from the beginning to end. + * This method MUST attempt to seek to the beginning of the stream before + * reading data and read the stream until the end is reached. + * Warning: This could attempt to load a large amount of data into memory. + * This method MUST NOT raise an exception in order to conform with PHP's + * string casting operations. + * + * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring + * @return string + */ + public function __toString() + { + try { + return $this->getContents(); + } catch (\Throwable $e) { + return ''; + } + } + + /** + * Closes the stream and any underlying resources. + */ + public function close() + { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * Separates any underlying resources from the stream. + * After the stream has been detached, the stream is in an unusable state. + * + * @return null|resource Underlying PHP stream, if any + */ + public function detach() + { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * Get the size of the stream if known. + * + * @return null|int returns the size in bytes if known, or null if unknown + */ + public function getSize() + { + if (!$this->size) { + $this->size = filesize($this->getContents()); + } + return $this->size; + } + + /** + * Returns the current position of the file read/write pointer. + * + * @return int Position of the file pointer + * @throws \RuntimeException on error + */ + public function tell() + { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * Returns true if the stream is at the end of the stream. + * + * @return bool + */ + public function eof() + { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * Returns whether or not the stream is seekable. + * + * @return bool + */ + public function isSeekable() + { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * Seek to a position in the stream. + * + * @see http://www.php.net/manual/en/function.fseek.php + * @param int $offset Stream offset + * @param int $whence Specifies how the cursor position will be calculated + * based on the seek offset. Valid values are identical to the built-in + * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to + * offset bytes SEEK_CUR: Set position to current location plus offset + * SEEK_END: Set position to end-of-stream plus offset. + * @throws \RuntimeException on failure + */ + public function seek($offset, $whence = SEEK_SET) + { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * Seek to the beginning of the stream. + * If the stream is not seekable, this method will raise an exception; + * otherwise, it will perform a seek(0). + * + * @throws \RuntimeException on failure + * @see http://www.php.net/manual/en/function.fseek.php + * @see seek() + */ + public function rewind() + { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * Returns whether or not the stream is writable. + * + * @return bool + */ + public function isWritable() + { + return false; + } + + /** + * Write data to the stream. + * + * @param string $string the string that is to be written + * @return int returns the number of bytes written to the stream + * @throws \RuntimeException on failure + */ + public function write($string) + { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * Returns whether or not the stream is readable. + * + * @return bool + */ + public function isReadable() + { + return true; + } + + /** + * Read data from the stream. + * + * @param int $length Read up to $length bytes from the object and return + * them. Fewer than $length bytes may be returned if underlying stream + * call returns fewer bytes. + * @return string returns the data read from the stream, or an empty string + * if no bytes are available + * @throws \RuntimeException if an error occurs + */ + public function read($length) + { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * Returns the remaining contents in a string. + * + * @return string + * @throws \RuntimeException if unable to read or an error occurs while + * reading + */ + public function getContents() + { + return $this->contents; + } + + /** + * Get stream metadata as an associative array or retrieve a specific key. + * The keys returned are identical to the keys returned from PHP's + * stream_get_meta_data() function. + * + * @see http://php.net/manual/en/function.stream-get-meta-data.php + * @param string $key specific metadata to retrieve + * @return null|array|mixed Returns an associative array if no key is + * provided. Returns a specific key value if a key is provided and the + * value is found, or null if the key is not found. + */ + public function getMetadata($key = null) + { + throw new \BadMethodCallException('Not implemented'); + } +} diff --git a/src/http-server/src/Contract/ResponseInterface.php b/src/http-server/src/Contract/ResponseInterface.php index 77e2f83e6..a73f3b6d2 100644 --- a/src/http-server/src/Contract/ResponseInterface.php +++ b/src/http-server/src/Contract/ResponseInterface.php @@ -44,4 +44,12 @@ interface ResponseInterface * Redirect to a URL. */ public function redirect(string $toUrl, int $status = 302, string $schema = 'http'): PsrResponseInterface; + + /** + * Create a new file download response. + * @param string $pathToFile + * @param string $name + * @return PsrResponseInterface + */ + public function download(string $pathToFile, string $name = ''): PsrResponseInterface; } diff --git a/src/http-server/src/Response.php b/src/http-server/src/Response.php index 245d971d9..cc3196b68 100644 --- a/src/http-server/src/Response.php +++ b/src/http-server/src/Response.php @@ -14,6 +14,7 @@ namespace Hyperf\HttpServer; use BadMethodCallException; use Hyperf\HttpMessage\Stream\SwooleStream; +use Hyperf\HttpMessage\Stream\SwooleFileStream; use Hyperf\HttpServer\Contract\ResponseInterface; use Hyperf\HttpServer\Exception\Http\EncodingException; use Hyperf\Utils\ApplicationContext; @@ -110,6 +111,39 @@ class Response implements PsrResponseInterface, ResponseInterface return $this->getResponse()->withStatus($status)->withAddedHeader('Location', $toUrl); } + /** + * Automatically sets the ETag header according to the checksum of the file. + * @param string $filePath + * @param bool $weak + * @return string + */ + protected function autoEtag(string $filePath, $weak = false): string + { + + $etag = sha1_file($filePath); + if (0 !== strpos($etag, '"')) { + $etag = '"' . $etag . '"'; + } + return (true === $weak ? 'W/' : '') . $etag; + } + + /** + * @param string $pathToFile + * @param string $name + * @return PsrResponseInterface + */ + public function download(string $pathToFile, string $name = ''): PsrResponseInterface + { + $filename = $name ?: basename($pathToFile); + return $this->withHeader('Content-Description', 'File Transfer') + ->withHeader('Content-Type', 'application/octet-stream') + ->withHeader('Content-Disposition', "attachment; filename={$filename}") + ->withHeader('Content-Transfer-Encoding', 'binary') + ->withHeader('Pragma', 'public') + ->withHeader('ETag', $this->autoEtag($pathToFile)) + ->withBody(new SwooleFileStream($pathToFile)); + } + /** * Retrieves the HTTP protocol version as a string. * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0"). From d7e6617132f82cf6c3ccbc085700d642ea61899c Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 28 Aug 2019 20:03:41 +0800 Subject: [PATCH 150/225] fixed doc method name error --- doc/zh/response.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/response.md b/doc/zh/response.md index 0973b54da..abf5897bf 100644 --- a/doc/zh/response.md +++ b/doc/zh/response.md @@ -137,7 +137,7 @@ class IndexController { public function download(ResponseInterface $response): Psr7ResponseInterface { - // redirect() 方法返回的是一个 Psr\Http\Message\ResponseInterface 对象,需再 return 回去 + // download() 方法返回的是一个 Psr\Http\Message\ResponseInterface 对象,需再 return 回去 return $response->download('/var/www/file.csv','filename.csv'); } } From cab20303cfaba6c85ec00c666b7f98d18b561f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 29 Aug 2019 10:55:56 +0800 Subject: [PATCH 151/225] Optimized code. --- CHANGELOG.md | 1 + src/http-message/src/Server/Response.php | 8 ++-- src/http-message/src/Stream/FileInterface.php | 18 ++++++++ .../src/Stream/SwooleFileStream.php | 30 +++++++------ src/http-server/src/Response.php | 43 +++++++++---------- 5 files changed, 61 insertions(+), 39 deletions(-) create mode 100644 src/http-message/src/Stream/FileInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 053dd2f33..4b9f328ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd - [#420](https://github.com/hyperf-cloud/hyperf/pull/420) Added listener for model. - [#441](https://github.com/hyperf-cloud/hyperf/pull/441) Automatically close the spare redis client when it is used in low frequency. +- [#455](https://github.com/hyperf-cloud/hyperf/pull/455) Added download method for Response. ## Changed diff --git a/src/http-message/src/Server/Response.php b/src/http-message/src/Server/Response.php index d3b928276..f2d3ddc6e 100755 --- a/src/http-message/src/Server/Response.php +++ b/src/http-message/src/Server/Response.php @@ -13,8 +13,8 @@ declare(strict_types=1); namespace Hyperf\HttpMessage\Server; use Hyperf\HttpMessage\Cookie\Cookie; +use Hyperf\HttpMessage\Stream\FileInterface; use Hyperf\HttpMessage\Stream\SwooleStream; -use Hyperf\HttpMessage\Stream\SwooleFileStream; class Response extends \Hyperf\HttpMessage\Base\Response { @@ -47,8 +47,8 @@ class Response extends \Hyperf\HttpMessage\Base\Response $this->buildSwooleResponse($this->swooleResponse, $this); $content = $this->getBody(); - if($content instanceof SwooleFileStream){ - return $this->swooleResponse->sendfile($content->getContents()); + if ($content instanceof FileInterface) { + return $this->swooleResponse->sendfile($content->getFilename()); } $this->swooleResponse->end($content->getContents()); } @@ -101,7 +101,7 @@ class Response extends \Hyperf\HttpMessage\Base\Response /* * Cookies */ - foreach ((array)$this->cookies as $domain => $paths) { + foreach ((array) $this->cookies as $domain => $paths) { foreach ($paths ?? [] as $path => $item) { foreach ($item ?? [] as $name => $cookie) { if ($cookie instanceof Cookie) { diff --git a/src/http-message/src/Stream/FileInterface.php b/src/http-message/src/Stream/FileInterface.php new file mode 100644 index 000000000..fa8f9d104 --- /dev/null +++ b/src/http-message/src/Stream/FileInterface.php @@ -0,0 +1,18 @@ +contents = $file_path; - $this->size = filesize($file_path); + $this->contents = $file; + $this->size = filesize($file); } /** @@ -88,7 +87,7 @@ class SwooleFileStream implements StreamInterface */ public function getSize() { - if (!$this->size) { + if (! $this->size) { $this->size = filesize($this->getContents()); } return $this->size; @@ -97,8 +96,8 @@ class SwooleFileStream implements StreamInterface /** * Returns the current position of the file read/write pointer. * - * @return int Position of the file pointer * @throws \RuntimeException on error + * @return int Position of the file pointer */ public function tell() { @@ -170,8 +169,8 @@ class SwooleFileStream implements StreamInterface * Write data to the stream. * * @param string $string the string that is to be written - * @return int returns the number of bytes written to the stream * @throws \RuntimeException on failure + * @return int returns the number of bytes written to the stream */ public function write($string) { @@ -194,9 +193,9 @@ class SwooleFileStream implements StreamInterface * @param int $length Read up to $length bytes from the object and return * them. Fewer than $length bytes may be returned if underlying stream * call returns fewer bytes. + * @throws \RuntimeException if an error occurs * @return string returns the data read from the stream, or an empty string * if no bytes are available - * @throws \RuntimeException if an error occurs */ public function read($length) { @@ -206,9 +205,9 @@ class SwooleFileStream implements StreamInterface /** * Returns the remaining contents in a string. * - * @return string * @throws \RuntimeException if unable to read or an error occurs while * reading + * @return string */ public function getContents() { @@ -230,4 +229,9 @@ class SwooleFileStream implements StreamInterface { throw new \BadMethodCallException('Not implemented'); } + + public function getFilename(): string + { + return $this->getContents(); + } } diff --git a/src/http-server/src/Response.php b/src/http-server/src/Response.php index cc3196b68..ce30debd4 100644 --- a/src/http-server/src/Response.php +++ b/src/http-server/src/Response.php @@ -13,8 +13,8 @@ declare(strict_types=1); namespace Hyperf\HttpServer; use BadMethodCallException; -use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\HttpMessage\Stream\SwooleFileStream; +use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\HttpServer\Contract\ResponseInterface; use Hyperf\HttpServer\Exception\Http\EncodingException; use Hyperf\Utils\ApplicationContext; @@ -112,36 +112,20 @@ class Response implements PsrResponseInterface, ResponseInterface } /** - * Automatically sets the ETag header according to the checksum of the file. - * @param string $filePath - * @param bool $weak - * @return string - */ - protected function autoEtag(string $filePath, $weak = false): string - { - - $etag = sha1_file($filePath); - if (0 !== strpos($etag, '"')) { - $etag = '"' . $etag . '"'; - } - return (true === $weak ? 'W/' : '') . $etag; - } - - /** - * @param string $pathToFile + * @param string $file * @param string $name * @return PsrResponseInterface */ - public function download(string $pathToFile, string $name = ''): PsrResponseInterface + public function download(string $file, string $name = ''): PsrResponseInterface { - $filename = $name ?: basename($pathToFile); + $filename = $name ?: basename($file); return $this->withHeader('Content-Description', 'File Transfer') ->withHeader('Content-Type', 'application/octet-stream') ->withHeader('Content-Disposition', "attachment; filename={$filename}") ->withHeader('Content-Transfer-Encoding', 'binary') ->withHeader('Pragma', 'public') - ->withHeader('ETag', $this->autoEtag($pathToFile)) - ->withBody(new SwooleFileStream($pathToFile)); + ->withHeader('ETag', $this->etag($file)) + ->withBody(new SwooleFileStream($file)); } /** @@ -378,6 +362,21 @@ class Response implements PsrResponseInterface, ResponseInterface return $this->getResponse()->getReasonPhrase(); } + /** + * Get ETag header according to the checksum of the file. + * @param string $file + * @param bool $weak + * @return string + */ + protected function etag(string $file, $weak = false): string + { + $etag = sha1_file($file); + if (strpos($etag, '"') !== 0) { + $etag = '"' . $etag . '"'; + } + return ($weak === true ? 'W/' : '') . $etag; + } + /** * @param array|Arrayable|Jsonable $data * @throws EncodingException when the data encoding error From e07f3ef2d3e5408a69df7c9cfdc4f96d0a7e027c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 29 Aug 2019 11:07:40 +0800 Subject: [PATCH 152/225] Added testing. --- src/http-message/tests/SwooleStreamTest.php | 54 +++++++++++++++++++ .../src/Contract/ResponseInterface.php | 4 +- 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/http-message/tests/SwooleStreamTest.php diff --git a/src/http-message/tests/SwooleStreamTest.php b/src/http-message/tests/SwooleStreamTest.php new file mode 100644 index 000000000..83b6fdf2f --- /dev/null +++ b/src/http-message/tests/SwooleStreamTest.php @@ -0,0 +1,54 @@ +shouldReceive('sendfile')->with($file)->once()->andReturn(null); + $swooleResponse->shouldReceive('status')->with(Mockery::any())->once()->andReturn(200); + + $response = new Response($swooleResponse); + $response = $response->withBody(new SwooleFileStream($file)); + + $this->assertSame(null, $response->send()); + } + + public function testSwooleStream() + { + $swooleResponse = Mockery::mock(SwooleResponse::class); + $content = '{"id":1}'; + $swooleResponse->shouldReceive('end')->with($content)->once()->andReturn(null); + $swooleResponse->shouldReceive('status')->with(Mockery::any())->once()->andReturn(200); + $swooleResponse->shouldReceive('header')->with('TOKEN', 'xxx')->once()->andReturn(null); + + $response = new Response($swooleResponse); + $response = $response->withBody(new SwooleStream($content))->withHeader('TOKEN', 'xxx'); + + $this->assertSame(null, $response->send()); + } +} diff --git a/src/http-server/src/Contract/ResponseInterface.php b/src/http-server/src/Contract/ResponseInterface.php index a73f3b6d2..ad11c9349 100644 --- a/src/http-server/src/Contract/ResponseInterface.php +++ b/src/http-server/src/Contract/ResponseInterface.php @@ -47,9 +47,9 @@ interface ResponseInterface /** * Create a new file download response. - * @param string $pathToFile + * @param string $file * @param string $name * @return PsrResponseInterface */ - public function download(string $pathToFile, string $name = ''): PsrResponseInterface; + public function download(string $file, string $name = ''): PsrResponseInterface; } From 876e180ef32ee55744be1d402a1642b8101e0ee5 Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Thu, 29 Aug 2019 15:04:33 +0800 Subject: [PATCH 153/225] Update summary.md --- doc/zh/summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/summary.md b/doc/zh/summary.md index e7ef8cc55..74d9059a2 100644 --- a/doc/zh/summary.md +++ b/doc/zh/summary.md @@ -74,7 +74,7 @@ * [开发者工具](zh/devtool.md) * [辅助类](zh/utils.md) * [限流器](zh/rate-limit.md) - * [Swoole Enterprise](zh/swoole-enterprise.md) + * [Swoole Tracker](zh/swoole-tracker.md) * [定时任务](zh/crontab.md) * [Task 机制](zh/task.md) * [枚举类](zh/constants.md) From 6ee18cf64f006ff92c5e73daee50bed63c01870a Mon Sep 17 00:00:00 2001 From: minororange Date: Thu, 29 Aug 2019 16:09:04 +0800 Subject: [PATCH 154/225] =?UTF-8?q?=E6=9B=B4=E6=96=B0Readme.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 百花齐放,百家争鸣 --- doc/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README.md b/doc/README.md index bb1cf7ca1..b93c08509 100644 --- a/doc/README.md +++ b/doc/README.md @@ -8,7 +8,7 @@ Hyperf 还提供了 `依赖注入`、`注解`、`AOP 面向切面编程`、`中 # 框架初衷 -尽管现在基于 PHP 语言开发的框架处于一个百花争鸣的时代,但仍旧未能看到一个优雅的设计与超高性能的共存的完美框架,亦没有看到一个真正为 PHP 微服务铺路的框架,此为 Hyperf 及其团队成员的初衷,我们将持续投入并为此付出努力,也欢迎你加入我们参与开源建设。 +尽管现在基于 PHP 语言开发的框架处于一个百家争鸣的时代,但仍旧未能看到一个优雅的设计与超高性能的共存的完美框架,亦没有看到一个真正为 PHP 微服务铺路的框架,此为 Hyperf 及其团队成员的初衷,我们将持续投入并为此付出努力,也欢迎你加入我们参与开源建设。 # 设计理念 From d862bbf9c2c1e67bac58f618130bf99108234e7d Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Thu, 29 Aug 2019 16:17:28 +0800 Subject: [PATCH 155/225] Add ClearStatCache to manage the stat cache --- src/utils/src/ClearStatCache.php | 63 ++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/utils/src/ClearStatCache.php diff --git a/src/utils/src/ClearStatCache.php b/src/utils/src/ClearStatCache.php new file mode 100644 index 000000000..6c4b2b050 --- /dev/null +++ b/src/utils/src/ClearStatCache.php @@ -0,0 +1,63 @@ + self::$interval + || self::$lastCleared + || (self::$lastCleared + self::$interval < $now) + ) { + self::forceClear($filename); + self::$lastCleared = $now; + } + } + + public static function forceClear(?string $filename = null): void + { + if ($filename !== null) { + clearstatcache(true, $filename); + } else { + clearstatcache(); + } + } + + public static function getInterval(): int + { + return self::$interval; + } + + public static function setInterval(int $interval): self + { + self::$interval = $interval; + } +} From 46ea290a5f8a887376364e1b52124cd0a9035645 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Thu, 29 Aug 2019 16:17:41 +0800 Subject: [PATCH 156/225] Remove useless comment --- src/http-server/src/Contract/ResponseInterface.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/http-server/src/Contract/ResponseInterface.php b/src/http-server/src/Contract/ResponseInterface.php index a73f3b6d2..47c76ee9b 100644 --- a/src/http-server/src/Contract/ResponseInterface.php +++ b/src/http-server/src/Contract/ResponseInterface.php @@ -47,9 +47,6 @@ interface ResponseInterface /** * Create a new file download response. - * @param string $pathToFile - * @param string $name - * @return PsrResponseInterface */ public function download(string $pathToFile, string $name = ''): PsrResponseInterface; } From c5d6e2e45cceca36384679728cb234f088ec6f62 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Thu, 29 Aug 2019 16:19:10 +0800 Subject: [PATCH 157/225] Add a guesser to guess mime type by extension, or guess extension by mine type --- .../src/MimeType/MimeTypeExtensionGuesser.php | 815 ++++++++++++++++++ 1 file changed, 815 insertions(+) create mode 100644 src/http-server/src/MimeType/MimeTypeExtensionGuesser.php diff --git a/src/http-server/src/MimeType/MimeTypeExtensionGuesser.php b/src/http-server/src/MimeType/MimeTypeExtensionGuesser.php new file mode 100644 index 000000000..2f79c0b7c --- /dev/null +++ b/src/http-server/src/MimeType/MimeTypeExtensionGuesser.php @@ -0,0 +1,815 @@ + 'ez', + 'application/applixware' => 'aw', + 'application/atom+xml' => 'atom', + 'application/atomcat+xml' => 'atomcat', + 'application/atomsvc+xml' => 'atomsvc', + 'application/ccxml+xml' => 'ccxml', + 'application/cdmi-capability' => 'cdmia', + 'application/cdmi-container' => 'cdmic', + 'application/cdmi-domain' => 'cdmid', + 'application/cdmi-object' => 'cdmio', + 'application/cdmi-queue' => 'cdmiq', + 'application/cu-seeme' => 'cu', + 'application/davmount+xml' => 'davmount', + 'application/docbook+xml' => 'dbk', + 'application/dssc+der' => 'dssc', + 'application/dssc+xml' => 'xdssc', + 'application/ecmascript' => 'ecma', + 'application/emma+xml' => 'emma', + 'application/epub+zip' => 'epub', + 'application/exi' => 'exi', + 'application/font-tdpfr' => 'pfr', + 'application/gml+xml' => 'gml', + 'application/gpx+xml' => 'gpx', + 'application/gxf' => 'gxf', + 'application/hyperstudio' => 'stk', + 'application/inkml+xml' => 'ink', + 'application/ipfix' => 'ipfix', + 'application/java-archive' => 'jar', + 'application/java-serialized-object' => 'ser', + 'application/java-vm' => 'class', + 'application/javascript' => 'js', + 'application/json' => 'json', + 'application/jsonml+json' => 'jsonml', + 'application/lost+xml' => 'lostxml', + 'application/mac-binhex40' => 'hqx', + 'application/mac-compactpro' => 'cpt', + 'application/mads+xml' => 'mads', + 'application/marc' => 'mrc', + 'application/marcxml+xml' => 'mrcx', + 'application/mathematica' => 'ma', + 'application/mathml+xml' => 'mathml', + 'application/mbox' => 'mbox', + 'application/mediaservercontrol+xml' => 'mscml', + 'application/metalink+xml' => 'metalink', + 'application/metalink4+xml' => 'meta4', + 'application/mets+xml' => 'mets', + 'application/mods+xml' => 'mods', + 'application/mp21' => 'm21', + 'application/mp4' => 'mp4s', + 'application/msword' => 'doc', + 'application/mxf' => 'mxf', + 'application/octet-stream' => 'bin', + 'application/oda' => 'oda', + 'application/oebps-package+xml' => 'opf', + 'application/ogg' => 'ogx', + 'application/omdoc+xml' => 'omdoc', + 'application/onenote' => 'onetoc', + 'application/oxps' => 'oxps', + 'application/patch-ops-error+xml' => 'xer', + 'application/pdf' => 'pdf', + 'application/pgp-encrypted' => 'pgp', + 'application/pgp-signature' => 'asc', + 'application/pics-rules' => 'prf', + 'application/pkcs10' => 'p10', + 'application/pkcs7-mime' => 'p7m', + 'application/pkcs7-signature' => 'p7s', + 'application/pkcs8' => 'p8', + 'application/pkix-attr-cert' => 'ac', + 'application/pkix-cert' => 'cer', + 'application/pkix-crl' => 'crl', + 'application/pkix-pkipath' => 'pkipath', + 'application/pkixcmp' => 'pki', + 'application/pls+xml' => 'pls', + 'application/postscript' => 'ai', + 'application/prs.cww' => 'cww', + 'application/pskc+xml' => 'pskcxml', + 'application/rdf+xml' => 'rdf', + 'application/reginfo+xml' => 'rif', + 'application/relax-ng-compact-syntax' => 'rnc', + 'application/resource-lists+xml' => 'rl', + 'application/resource-lists-diff+xml' => 'rld', + 'application/rls-services+xml' => 'rs', + 'application/rpki-ghostbusters' => 'gbr', + 'application/rpki-manifest' => 'mft', + 'application/rpki-roa' => 'roa', + 'application/rsd+xml' => 'rsd', + 'application/rss+xml' => 'rss', + 'application/rtf' => 'rtf', + 'application/sbml+xml' => 'sbml', + 'application/scvp-cv-request' => 'scq', + 'application/scvp-cv-response' => 'scs', + 'application/scvp-vp-request' => 'spq', + 'application/scvp-vp-response' => 'spp', + 'application/sdp' => 'sdp', + 'application/set-payment-initiation' => 'setpay', + 'application/set-registration-initiation' => 'setreg', + 'application/shf+xml' => 'shf', + 'application/smil+xml' => 'smi', + 'application/sparql-query' => 'rq', + 'application/sparql-results+xml' => 'srx', + 'application/srgs' => 'gram', + 'application/srgs+xml' => 'grxml', + 'application/sru+xml' => 'sru', + 'application/ssdl+xml' => 'ssdl', + 'application/ssml+xml' => 'ssml', + 'application/tei+xml' => 'tei', + 'application/thraud+xml' => 'tfi', + 'application/timestamped-data' => 'tsd', + 'application/vnd.3gpp.pic-bw-large' => 'plb', + 'application/vnd.3gpp.pic-bw-small' => 'psb', + 'application/vnd.3gpp.pic-bw-var' => 'pvb', + 'application/vnd.3gpp2.tcap' => 'tcap', + 'application/vnd.3m.post-it-notes' => 'pwn', + 'application/vnd.accpac.simply.aso' => 'aso', + 'application/vnd.accpac.simply.imp' => 'imp', + 'application/vnd.acucobol' => 'acu', + 'application/vnd.acucorp' => 'atc', + 'application/vnd.adobe.air-application-installer-package+zip' => 'air', + 'application/vnd.adobe.formscentral.fcdt' => 'fcdt', + 'application/vnd.adobe.fxp' => 'fxp', + 'application/vnd.adobe.xdp+xml' => 'xdp', + 'application/vnd.adobe.xfdf' => 'xfdf', + 'application/vnd.ahead.space' => 'ahead', + 'application/vnd.airzip.filesecure.azf' => 'azf', + 'application/vnd.airzip.filesecure.azs' => 'azs', + 'application/vnd.amazon.ebook' => 'azw', + 'application/vnd.americandynamics.acc' => 'acc', + 'application/vnd.amiga.ami' => 'ami', + 'application/vnd.android.package-archive' => 'apk', + 'application/vnd.anser-web-certificate-issue-initiation' => 'cii', + 'application/vnd.anser-web-funds-transfer-initiation' => 'fti', + 'application/vnd.antix.game-component' => 'atx', + 'application/vnd.apple.installer+xml' => 'mpkg', + 'application/vnd.apple.mpegurl' => 'm3u8', + 'application/vnd.aristanetworks.swi' => 'swi', + 'application/vnd.astraea-software.iota' => 'iota', + 'application/vnd.audiograph' => 'aep', + 'application/vnd.blueice.multipass' => 'mpm', + 'application/vnd.bmi' => 'bmi', + 'application/vnd.businessobjects' => 'rep', + 'application/vnd.chemdraw+xml' => 'cdxml', + 'application/vnd.chipnuts.karaoke-mmd' => 'mmd', + 'application/vnd.cinderella' => 'cdy', + 'application/vnd.claymore' => 'cla', + 'application/vnd.cloanto.rp9' => 'rp9', + 'application/vnd.clonk.c4group' => 'c4g', + 'application/vnd.cluetrust.cartomobile-config' => 'c11amc', + 'application/vnd.cluetrust.cartomobile-config-pkg' => 'c11amz', + 'application/vnd.commonspace' => 'csp', + 'application/vnd.contact.cmsg' => 'cdbcmsg', + 'application/vnd.cosmocaller' => 'cmc', + 'application/vnd.crick.clicker' => 'clkx', + 'application/vnd.crick.clicker.keyboard' => 'clkk', + 'application/vnd.crick.clicker.palette' => 'clkp', + 'application/vnd.crick.clicker.template' => 'clkt', + 'application/vnd.crick.clicker.wordbank' => 'clkw', + 'application/vnd.criticaltools.wbs+xml' => 'wbs', + 'application/vnd.ctc-posml' => 'pml', + 'application/vnd.cups-ppd' => 'ppd', + 'application/vnd.curl.car' => 'car', + 'application/vnd.curl.pcurl' => 'pcurl', + 'application/vnd.dart' => 'dart', + 'application/vnd.data-vision.rdz' => 'rdz', + 'application/vnd.dece.data' => 'uvf', + 'application/vnd.dece.ttml+xml' => 'uvt', + 'application/vnd.dece.unspecified' => 'uvx', + 'application/vnd.dece.zip' => 'uvz', + 'application/vnd.denovo.fcselayout-link' => 'fe_launch', + 'application/vnd.dna' => 'dna', + 'application/vnd.dolby.mlp' => 'mlp', + 'application/vnd.dpgraph' => 'dpg', + 'application/vnd.dreamfactory' => 'dfac', + 'application/vnd.ds-keypoint' => 'kpxx', + 'application/vnd.dvb.ait' => 'ait', + 'application/vnd.dvb.service' => 'svc', + 'application/vnd.dynageo' => 'geo', + 'application/vnd.ecowin.chart' => 'mag', + 'application/vnd.enliven' => 'nml', + 'application/vnd.epson.esf' => 'esf', + 'application/vnd.epson.msf' => 'msf', + 'application/vnd.epson.quickanime' => 'qam', + 'application/vnd.epson.salt' => 'slt', + 'application/vnd.epson.ssf' => 'ssf', + 'application/vnd.eszigno3+xml' => 'es3', + 'application/vnd.ezpix-album' => 'ez2', + 'application/vnd.ezpix-package' => 'ez3', + 'application/vnd.fdf' => 'fdf', + 'application/vnd.fdsn.mseed' => 'mseed', + 'application/vnd.fdsn.seed' => 'seed', + 'application/vnd.flographit' => 'gph', + 'application/vnd.fluxtime.clip' => 'ftc', + 'application/vnd.framemaker' => 'fm', + 'application/vnd.frogans.fnc' => 'fnc', + 'application/vnd.frogans.ltf' => 'ltf', + 'application/vnd.fsc.weblaunch' => 'fsc', + 'application/vnd.fujitsu.oasys' => 'oas', + 'application/vnd.fujitsu.oasys2' => 'oa2', + 'application/vnd.fujitsu.oasys3' => 'oa3', + 'application/vnd.fujitsu.oasysgp' => 'fg5', + 'application/vnd.fujitsu.oasysprs' => 'bh2', + 'application/vnd.fujixerox.ddd' => 'ddd', + 'application/vnd.fujixerox.docuworks' => 'xdw', + 'application/vnd.fujixerox.docuworks.binder' => 'xbd', + 'application/vnd.fuzzysheet' => 'fzs', + 'application/vnd.genomatix.tuxedo' => 'txd', + 'application/vnd.geogebra.file' => 'ggb', + 'application/vnd.geogebra.tool' => 'ggt', + 'application/vnd.geometry-explorer' => 'gex', + 'application/vnd.geonext' => 'gxt', + 'application/vnd.geoplan' => 'g2w', + 'application/vnd.geospace' => 'g3w', + 'application/vnd.gmx' => 'gmx', + 'application/vnd.google-earth.kml+xml' => 'kml', + 'application/vnd.google-earth.kmz' => 'kmz', + 'application/vnd.grafeq' => 'gqf', + 'application/vnd.groove-account' => 'gac', + 'application/vnd.groove-help' => 'ghf', + 'application/vnd.groove-identity-message' => 'gim', + 'application/vnd.groove-injector' => 'grv', + 'application/vnd.groove-tool-message' => 'gtm', + 'application/vnd.groove-tool-template' => 'tpl', + 'application/vnd.groove-vcard' => 'vcg', + 'application/vnd.hal+xml' => 'hal', + 'application/vnd.handheld-entertainment+xml' => 'zmm', + 'application/vnd.hbci' => 'hbci', + 'application/vnd.hhe.lesson-player' => 'les', + 'application/vnd.hp-hpgl' => 'hpgl', + 'application/vnd.hp-hpid' => 'hpid', + 'application/vnd.hp-hps' => 'hps', + 'application/vnd.hp-jlyt' => 'jlt', + 'application/vnd.hp-pcl' => 'pcl', + 'application/vnd.hp-pclxl' => 'pclxl', + 'application/vnd.hydrostatix.sof-data' => 'sfd-hdstx', + 'application/vnd.ibm.minipay' => 'mpy', + 'application/vnd.ibm.modcap' => 'afp', + 'application/vnd.ibm.rights-management' => 'irm', + 'application/vnd.ibm.secure-container' => 'sc', + 'application/vnd.iccprofile' => 'icc', + 'application/vnd.igloader' => 'igl', + 'application/vnd.immervision-ivp' => 'ivp', + 'application/vnd.immervision-ivu' => 'ivu', + 'application/vnd.insors.igm' => 'igm', + 'application/vnd.intercon.formnet' => 'xpw', + 'application/vnd.intergeo' => 'i2g', + 'application/vnd.intu.qbo' => 'qbo', + 'application/vnd.intu.qfx' => 'qfx', + 'application/vnd.ipunplugged.rcprofile' => 'rcprofile', + 'application/vnd.irepository.package+xml' => 'irp', + 'application/vnd.is-xpr' => 'xpr', + 'application/vnd.isac.fcs' => 'fcs', + 'application/vnd.jam' => 'jam', + 'application/vnd.jcp.javame.midlet-rms' => 'rms', + 'application/vnd.jisp' => 'jisp', + 'application/vnd.joost.joda-archive' => 'joda', + 'application/vnd.kahootz' => 'ktz', + 'application/vnd.kde.karbon' => 'karbon', + 'application/vnd.kde.kchart' => 'chrt', + 'application/vnd.kde.kformula' => 'kfo', + 'application/vnd.kde.kivio' => 'flw', + 'application/vnd.kde.kontour' => 'kon', + 'application/vnd.kde.kpresenter' => 'kpr', + 'application/vnd.kde.kspread' => 'ksp', + 'application/vnd.kde.kword' => 'kwd', + 'application/vnd.kenameaapp' => 'htke', + 'application/vnd.kidspiration' => 'kia', + 'application/vnd.kinar' => 'kne', + 'application/vnd.koan' => 'skp', + 'application/vnd.kodak-descriptor' => 'sse', + 'application/vnd.las.las+xml' => 'lasxml', + 'application/vnd.llamagraphics.life-balance.desktop' => 'lbd', + 'application/vnd.llamagraphics.life-balance.exchange+xml' => 'lbe', + 'application/vnd.lotus-1-2-3' => '123', + 'application/vnd.lotus-approach' => 'apr', + 'application/vnd.lotus-freelance' => 'pre', + 'application/vnd.lotus-notes' => 'nsf', + 'application/vnd.lotus-organizer' => 'org', + 'application/vnd.lotus-screencam' => 'scm', + 'application/vnd.lotus-wordpro' => 'lwp', + 'application/vnd.macports.portpkg' => 'portpkg', + 'application/vnd.mcd' => 'mcd', + 'application/vnd.medcalcdata' => 'mc1', + 'application/vnd.mediastation.cdkey' => 'cdkey', + 'application/vnd.mfer' => 'mwf', + 'application/vnd.mfmp' => 'mfm', + 'application/vnd.micrografx.flo' => 'flo', + 'application/vnd.micrografx.igx' => 'igx', + 'application/vnd.mif' => 'mif', + 'application/vnd.mobius.daf' => 'daf', + 'application/vnd.mobius.dis' => 'dis', + 'application/vnd.mobius.mbk' => 'mbk', + 'application/vnd.mobius.mqy' => 'mqy', + 'application/vnd.mobius.msl' => 'msl', + 'application/vnd.mobius.plc' => 'plc', + 'application/vnd.mobius.txf' => 'txf', + 'application/vnd.mophun.application' => 'mpn', + 'application/vnd.mophun.certificate' => 'mpc', + 'application/vnd.mozilla.xul+xml' => 'xul', + 'application/vnd.ms-artgalry' => 'cil', + 'application/vnd.ms-cab-compressed' => 'cab', + 'application/vnd.ms-excel' => 'xls', + 'application/vnd.ms-excel.addin.macroenabled.12' => 'xlam', + 'application/vnd.ms-excel.sheet.binary.macroenabled.12' => 'xlsb', + 'application/vnd.ms-excel.sheet.macroenabled.12' => 'xlsm', + 'application/vnd.ms-excel.template.macroenabled.12' => 'xltm', + 'application/vnd.ms-fontobject' => 'eot', + 'application/vnd.ms-htmlhelp' => 'chm', + 'application/vnd.ms-ims' => 'ims', + 'application/vnd.ms-lrm' => 'lrm', + 'application/vnd.ms-officetheme' => 'thmx', + 'application/vnd.ms-pki.seccat' => 'cat', + 'application/vnd.ms-pki.stl' => 'stl', + 'application/vnd.ms-powerpoint' => 'ppt', + 'application/vnd.ms-powerpoint.addin.macroenabled.12' => 'ppam', + 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => 'pptm', + 'application/vnd.ms-powerpoint.slide.macroenabled.12' => 'sldm', + 'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => 'ppsm', + 'application/vnd.ms-powerpoint.template.macroenabled.12' => 'potm', + 'application/vnd.ms-project' => 'mpp', + 'application/vnd.ms-word.document.macroenabled.12' => 'docm', + 'application/vnd.ms-word.template.macroenabled.12' => 'dotm', + 'application/vnd.ms-works' => 'wps', + 'application/vnd.ms-wpl' => 'wpl', + 'application/vnd.ms-xpsdocument' => 'xps', + 'application/vnd.mseq' => 'mseq', + 'application/vnd.musician' => 'mus', + 'application/vnd.muvee.style' => 'msty', + 'application/vnd.mynfc' => 'taglet', + 'application/vnd.neurolanguage.nlu' => 'nlu', + 'application/vnd.nitf' => 'ntf', + 'application/vnd.noblenet-directory' => 'nnd', + 'application/vnd.noblenet-sealer' => 'nns', + 'application/vnd.noblenet-web' => 'nnw', + 'application/vnd.nokia.n-gage.data' => 'ngdat', + 'application/vnd.nokia.n-gage.symbian.install' => 'n-gage', + 'application/vnd.nokia.radio-preset' => 'rpst', + 'application/vnd.nokia.radio-presets' => 'rpss', + 'application/vnd.novadigm.edm' => 'edm', + 'application/vnd.novadigm.edx' => 'edx', + 'application/vnd.novadigm.ext' => 'ext', + 'application/vnd.oasis.opendocument.chart' => 'odc', + 'application/vnd.oasis.opendocument.chart-template' => 'otc', + 'application/vnd.oasis.opendocument.database' => 'odb', + 'application/vnd.oasis.opendocument.formula' => 'odf', + 'application/vnd.oasis.opendocument.formula-template' => 'odft', + 'application/vnd.oasis.opendocument.graphics' => 'odg', + 'application/vnd.oasis.opendocument.graphics-template' => 'otg', + 'application/vnd.oasis.opendocument.image' => 'odi', + 'application/vnd.oasis.opendocument.image-template' => 'oti', + 'application/vnd.oasis.opendocument.presentation' => 'odp', + 'application/vnd.oasis.opendocument.presentation-template' => 'otp', + 'application/vnd.oasis.opendocument.spreadsheet' => 'ods', + 'application/vnd.oasis.opendocument.spreadsheet-template' => 'ots', + 'application/vnd.oasis.opendocument.text' => 'odt', + 'application/vnd.oasis.opendocument.text-master' => 'odm', + 'application/vnd.oasis.opendocument.text-template' => 'ott', + 'application/vnd.oasis.opendocument.text-web' => 'oth', + 'application/vnd.olpc-sugar' => 'xo', + 'application/vnd.oma.dd2+xml' => 'dd2', + 'application/vnd.openofficeorg.extension' => 'oxt', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx', + 'application/vnd.openxmlformats-officedocument.presentationml.slide' => 'sldx', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'ppsx', + 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'potx', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'xltx', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'dotx', + 'application/vnd.osgeo.mapguide.package' => 'mgp', + 'application/vnd.osgi.dp' => 'dp', + 'application/vnd.osgi.subsystem' => 'esa', + 'application/vnd.palm' => 'pdb', + 'application/vnd.pawaafile' => 'paw', + 'application/vnd.pg.format' => 'str', + 'application/vnd.pg.osasli' => 'ei6', + 'application/vnd.picsel' => 'efif', + 'application/vnd.pmi.widget' => 'wg', + 'application/vnd.pocketlearn' => 'plf', + 'application/vnd.powerbuilder6' => 'pbd', + 'application/vnd.previewsystems.box' => 'box', + 'application/vnd.proteus.magazine' => 'mgz', + 'application/vnd.publishare-delta-tree' => 'qps', + 'application/vnd.pvi.ptid1' => 'ptid', + 'application/vnd.quark.quarkxpress' => 'qxd', + 'application/vnd.realvnc.bed' => 'bed', + 'application/vnd.recordare.musicxml' => 'mxl', + 'application/vnd.recordare.musicxml+xml' => 'musicxml', + 'application/vnd.rig.cryptonote' => 'cryptonote', + 'application/vnd.rim.cod' => 'cod', + 'application/vnd.rn-realmedia' => 'rm', + 'application/vnd.rn-realmedia-vbr' => 'rmvb', + 'application/vnd.route66.link66+xml' => 'link66', + 'application/vnd.sailingtracker.track' => 'st', + 'application/vnd.seemail' => 'see', + 'application/vnd.sema' => 'sema', + 'application/vnd.semd' => 'semd', + 'application/vnd.semf' => 'semf', + 'application/vnd.shana.informed.formdata' => 'ifm', + 'application/vnd.shana.informed.formtemplate' => 'itp', + 'application/vnd.shana.informed.interchange' => 'iif', + 'application/vnd.shana.informed.package' => 'ipk', + 'application/vnd.simtech-mindmapper' => 'twd', + 'application/vnd.smaf' => 'mmf', + 'application/vnd.smart.teacher' => 'teacher', + 'application/vnd.solent.sdkm+xml' => 'sdkm', + 'application/vnd.spotfire.dxp' => 'dxp', + 'application/vnd.spotfire.sfs' => 'sfs', + 'application/vnd.stardivision.calc' => 'sdc', + 'application/vnd.stardivision.draw' => 'sda', + 'application/vnd.stardivision.impress' => 'sdd', + 'application/vnd.stardivision.math' => 'smf', + 'application/vnd.stardivision.writer' => 'sdw', + 'application/vnd.stardivision.writer-global' => 'sgl', + 'application/vnd.stepmania.package' => 'smzip', + 'application/vnd.stepmania.stepchart' => 'sm', + 'application/vnd.sun.xml.calc' => 'sxc', + 'application/vnd.sun.xml.calc.template' => 'stc', + 'application/vnd.sun.xml.draw' => 'sxd', + 'application/vnd.sun.xml.draw.template' => 'std', + 'application/vnd.sun.xml.impress' => 'sxi', + 'application/vnd.sun.xml.impress.template' => 'sti', + 'application/vnd.sun.xml.math' => 'sxm', + 'application/vnd.sun.xml.writer' => 'sxw', + 'application/vnd.sun.xml.writer.global' => 'sxg', + 'application/vnd.sun.xml.writer.template' => 'stw', + 'application/vnd.sus-calendar' => 'sus', + 'application/vnd.svd' => 'svd', + 'application/vnd.symbian.install' => 'sis', + 'application/vnd.syncml+xml' => 'xsm', + 'application/vnd.syncml.dm+wbxml' => 'bdm', + 'application/vnd.syncml.dm+xml' => 'xdm', + 'application/vnd.tao.intent-module-archive' => 'tao', + 'application/vnd.tcpdump.pcap' => 'pcap', + 'application/vnd.tmobile-livetv' => 'tmo', + 'application/vnd.trid.tpt' => 'tpt', + 'application/vnd.triscape.mxs' => 'mxs', + 'application/vnd.trueapp' => 'tra', + 'application/vnd.ufdl' => 'ufd', + 'application/vnd.uiq.theme' => 'utz', + 'application/vnd.umajin' => 'umj', + 'application/vnd.unity' => 'unityweb', + 'application/vnd.uoml+xml' => 'uoml', + 'application/vnd.vcx' => 'vcx', + 'application/vnd.visio' => 'vsd', + 'application/vnd.visionary' => 'vis', + 'application/vnd.vsf' => 'vsf', + 'application/vnd.wap.wbxml' => 'wbxml', + 'application/vnd.wap.wmlc' => 'wmlc', + 'application/vnd.wap.wmlscriptc' => 'wmlsc', + 'application/vnd.webturbo' => 'wtb', + 'application/vnd.wolfram.player' => 'nbp', + 'application/vnd.wordperfect' => 'wpd', + 'application/vnd.wqd' => 'wqd', + 'application/vnd.wt.stf' => 'stf', + 'application/vnd.xara' => 'xar', + 'application/vnd.xfdl' => 'xfdl', + 'application/vnd.yamaha.hv-dic' => 'hvd', + 'application/vnd.yamaha.hv-script' => 'hvs', + 'application/vnd.yamaha.hv-voice' => 'hvp', + 'application/vnd.yamaha.openscoreformat' => 'osf', + 'application/vnd.yamaha.openscoreformat.osfpvg+xml' => 'osfpvg', + 'application/vnd.yamaha.smaf-audio' => 'saf', + 'application/vnd.yamaha.smaf-phrase' => 'spf', + 'application/vnd.yellowriver-custom-menu' => 'cmp', + 'application/vnd.zul' => 'zir', + 'application/vnd.zzazz.deck+xml' => 'zaz', + 'application/voicexml+xml' => 'vxml', + 'application/widget' => 'wgt', + 'application/winhlp' => 'hlp', + 'application/wsdl+xml' => 'wsdl', + 'application/wspolicy+xml' => 'wspolicy', + 'application/x-7z-compressed' => '7z', + 'application/x-abiword' => 'abw', + 'application/x-ace-compressed' => 'ace', + 'application/x-apple-diskimage' => 'dmg', + 'application/x-authorware-bin' => 'aab', + 'application/x-authorware-map' => 'aam', + 'application/x-authorware-seg' => 'aas', + 'application/x-bcpio' => 'bcpio', + 'application/x-bittorrent' => 'torrent', + 'application/x-blorb' => 'blb', + 'application/x-bzip' => 'bz', + 'application/x-bzip2' => 'bz2', + 'application/x-cbr' => 'cbr', + 'application/x-cdlink' => 'vcd', + 'application/x-cfs-compressed' => 'cfs', + 'application/x-chat' => 'chat', + 'application/x-chess-pgn' => 'pgn', + 'application/x-conference' => 'nsc', + 'application/x-cpio' => 'cpio', + 'application/x-csh' => 'csh', + 'application/x-debian-package' => 'deb', + 'application/x-dgc-compressed' => 'dgc', + 'application/x-director' => 'dir', + 'application/x-doom' => 'wad', + 'application/x-dtbncx+xml' => 'ncx', + 'application/x-dtbook+xml' => 'dtb', + 'application/x-dtbresource+xml' => 'res', + 'application/x-dvi' => 'dvi', + 'application/x-envoy' => 'evy', + 'application/x-eva' => 'eva', + 'application/x-font-bdf' => 'bdf', + 'application/x-font-ghostscript' => 'gsf', + 'application/x-font-linux-psf' => 'psf', + 'application/x-font-otf' => 'otf', + 'application/x-font-pcf' => 'pcf', + 'application/x-font-snf' => 'snf', + 'application/x-font-ttf' => 'ttf', + 'application/x-font-type1' => 'pfa', + 'application/x-font-woff' => 'woff', + 'application/x-freearc' => 'arc', + 'application/x-futuresplash' => 'spl', + 'application/x-gca-compressed' => 'gca', + 'application/x-glulx' => 'ulx', + 'application/x-gnumeric' => 'gnumeric', + 'application/x-gramps-xml' => 'gramps', + 'application/x-gtar' => 'gtar', + 'application/x-hdf' => 'hdf', + 'application/x-install-instructions' => 'install', + 'application/x-iso9660-image' => 'iso', + 'application/x-java-jnlp-file' => 'jnlp', + 'application/x-latex' => 'latex', + 'application/x-lzh-compressed' => 'lzh', + 'application/x-mie' => 'mie', + 'application/x-mobipocket-ebook' => 'prc', + 'application/x-ms-application' => 'application', + 'application/x-ms-shortcut' => 'lnk', + 'application/x-ms-wmd' => 'wmd', + 'application/x-ms-wmz' => 'wmz', + 'application/x-ms-xbap' => 'xbap', + 'application/x-msaccess' => 'mdb', + 'application/x-msbinder' => 'obd', + 'application/x-mscardfile' => 'crd', + 'application/x-msclip' => 'clp', + 'application/x-msdownload' => 'exe', + 'application/x-msmediaview' => 'mvb', + 'application/x-msmetafile' => 'wmf', + 'application/x-msmoney' => 'mny', + 'application/x-mspublisher' => 'pub', + 'application/x-msschedule' => 'scd', + 'application/x-msterminal' => 'trm', + 'application/x-mswrite' => 'wri', + 'application/x-netcdf' => 'nc', + 'application/x-nzb' => 'nzb', + 'application/x-pkcs12' => 'p12', + 'application/x-pkcs7-certificates' => 'p7b', + 'application/x-pkcs7-certreqresp' => 'p7r', + 'application/x-rar-compressed' => 'rar', + 'application/x-rar' => 'rar', + 'application/x-research-info-systems' => 'ris', + 'application/x-sh' => 'sh', + 'application/x-shar' => 'shar', + 'application/x-shockwave-flash' => 'swf', + 'application/x-silverlight-app' => 'xap', + 'application/x-sql' => 'sql', + 'application/x-stuffit' => 'sit', + 'application/x-stuffitx' => 'sitx', + 'application/x-subrip' => 'srt', + 'application/x-sv4cpio' => 'sv4cpio', + 'application/x-sv4crc' => 'sv4crc', + 'application/x-t3vm-image' => 't3', + 'application/x-tads' => 'gam', + 'application/x-tar' => 'tar', + 'application/x-tcl' => 'tcl', + 'application/x-tex' => 'tex', + 'application/x-tex-tfm' => 'tfm', + 'application/x-texinfo' => 'texinfo', + 'application/x-tgif' => 'obj', + 'application/x-ustar' => 'ustar', + 'application/x-wais-source' => 'src', + 'application/x-x509-ca-cert' => 'der', + 'application/x-xfig' => 'fig', + 'application/x-xliff+xml' => 'xlf', + 'application/x-xpinstall' => 'xpi', + 'application/x-xz' => 'xz', + 'application/x-zip-compressed' => 'zip', + 'application/x-zmachine' => 'z1', + 'application/xaml+xml' => 'xaml', + 'application/xcap-diff+xml' => 'xdf', + 'application/xenc+xml' => 'xenc', + 'application/xhtml+xml' => 'xhtml', + 'application/xml' => 'xml', + 'application/xml-dtd' => 'dtd', + 'application/xop+xml' => 'xop', + 'application/xproc+xml' => 'xpl', + 'application/xslt+xml' => 'xslt', + 'application/xspf+xml' => 'xspf', + 'application/xv+xml' => 'mxml', + 'application/yang' => 'yang', + 'application/yin+xml' => 'yin', + 'application/zip' => 'zip', + 'audio/adpcm' => 'adp', + 'audio/basic' => 'au', + 'audio/midi' => 'mid', + 'audio/mp4' => 'mp4a', + 'audio/mpeg' => 'mpga', + 'audio/ogg' => 'oga', + 'audio/s3m' => 's3m', + 'audio/silk' => 'sil', + 'audio/vnd.dece.audio' => 'uva', + 'audio/vnd.digital-winds' => 'eol', + 'audio/vnd.dra' => 'dra', + 'audio/vnd.dts' => 'dts', + 'audio/vnd.dts.hd' => 'dtshd', + 'audio/vnd.lucent.voice' => 'lvp', + 'audio/vnd.ms-playready.media.pya' => 'pya', + 'audio/vnd.nuera.ecelp4800' => 'ecelp4800', + 'audio/vnd.nuera.ecelp7470' => 'ecelp7470', + 'audio/vnd.nuera.ecelp9600' => 'ecelp9600', + 'audio/vnd.rip' => 'rip', + 'audio/webm' => 'weba', + 'audio/x-aac' => 'aac', + 'audio/x-aiff' => 'aif', + 'audio/x-caf' => 'caf', + 'audio/x-flac' => 'flac', + 'audio/x-matroska' => 'mka', + 'audio/x-mpegurl' => 'm3u', + 'audio/x-ms-wax' => 'wax', + 'audio/x-ms-wma' => 'wma', + 'audio/x-pn-realaudio' => 'ram', + 'audio/x-pn-realaudio-plugin' => 'rmp', + 'audio/x-wav' => 'wav', + 'audio/xm' => 'xm', + 'chemical/x-cdx' => 'cdx', + 'chemical/x-cif' => 'cif', + 'chemical/x-cmdf' => 'cmdf', + 'chemical/x-cml' => 'cml', + 'chemical/x-csml' => 'csml', + 'chemical/x-xyz' => 'xyz', + 'image/bmp' => 'bmp', + 'image/x-ms-bmp' => 'bmp', + 'image/cgm' => 'cgm', + 'image/g3fax' => 'g3', + 'image/gif' => 'gif', + 'image/ief' => 'ief', + 'image/jpeg' => 'jpg', + 'image/pjpeg' => 'jpeg', + 'image/ktx' => 'ktx', + 'image/png' => 'png', + 'image/prs.btif' => 'btif', + 'image/sgi' => 'sgi', + 'image/svg+xml' => 'svg', + 'image/tiff' => 'tiff', + 'image/vnd.adobe.photoshop' => 'psd', + 'image/vnd.dece.graphic' => 'uvi', + 'image/vnd.dvb.subtitle' => 'sub', + 'image/vnd.djvu' => 'djvu', + 'image/vnd.dwg' => 'dwg', + 'image/vnd.dxf' => 'dxf', + 'image/vnd.fastbidsheet' => 'fbs', + 'image/vnd.fpx' => 'fpx', + 'image/vnd.fst' => 'fst', + 'image/vnd.fujixerox.edmics-mmr' => 'mmr', + 'image/vnd.fujixerox.edmics-rlc' => 'rlc', + 'image/vnd.ms-modi' => 'mdi', + 'image/vnd.ms-photo' => 'wdp', + 'image/vnd.net-fpx' => 'npx', + 'image/vnd.wap.wbmp' => 'wbmp', + 'image/vnd.xiff' => 'xif', + 'image/webp' => 'webp', + 'image/x-3ds' => '3ds', + 'image/x-cmu-raster' => 'ras', + 'image/x-cmx' => 'cmx', + 'image/x-freehand' => 'fh', + 'image/x-icon' => 'ico', + 'image/x-mrsid-image' => 'sid', + 'image/x-pcx' => 'pcx', + 'image/x-pict' => 'pic', + 'image/x-portable-anymap' => 'pnm', + 'image/x-portable-bitmap' => 'pbm', + 'image/x-portable-graymap' => 'pgm', + 'image/x-portable-pixmap' => 'ppm', + 'image/x-rgb' => 'rgb', + 'image/x-tga' => 'tga', + 'image/x-xbitmap' => 'xbm', + 'image/x-xpixmap' => 'xpm', + 'image/x-xwindowdump' => 'xwd', + 'message/rfc822' => 'eml', + 'model/iges' => 'igs', + 'model/mesh' => 'msh', + 'model/vnd.collada+xml' => 'dae', + 'model/vnd.dwf' => 'dwf', + 'model/vnd.gdl' => 'gdl', + 'model/vnd.gtw' => 'gtw', + 'model/vnd.mts' => 'mts', + 'model/vnd.vtu' => 'vtu', + 'model/vrml' => 'wrl', + 'model/x3d+binary' => 'x3db', + 'model/x3d+vrml' => 'x3dv', + 'model/x3d+xml' => 'x3d', + 'text/cache-manifest' => 'appcache', + 'text/calendar' => 'ics', + 'text/css' => 'css', + 'text/csv' => 'csv', + 'text/html' => 'html', + 'text/n3' => 'n3', + 'text/plain' => 'txt', + 'text/prs.lines.tag' => 'dsc', + 'text/richtext' => 'rtx', + 'text/rtf' => 'rtf', + 'text/sgml' => 'sgml', + 'text/tab-separated-values' => 'tsv', + 'text/troff' => 't', + 'text/turtle' => 'ttl', + 'text/uri-list' => 'uri', + 'text/vcard' => 'vcard', + 'text/vnd.curl' => 'curl', + 'text/vnd.curl.dcurl' => 'dcurl', + 'text/vnd.curl.scurl' => 'scurl', + 'text/vnd.curl.mcurl' => 'mcurl', + 'text/vnd.dvb.subtitle' => 'sub', + 'text/vnd.fly' => 'fly', + 'text/vnd.fmi.flexstor' => 'flx', + 'text/vnd.graphviz' => 'gv', + 'text/vnd.in3d.3dml' => '3dml', + 'text/vnd.in3d.spot' => 'spot', + 'text/vnd.sun.j2me.app-descriptor' => 'jad', + 'text/vnd.wap.wml' => 'wml', + 'text/vnd.wap.wmlscript' => 'wmls', + 'text/vtt' => 'vtt', + 'text/x-asm' => 's', + 'text/x-c' => 'c', + 'text/x-fortran' => 'f', + 'text/x-pascal' => 'p', + 'text/x-java-source' => 'java', + 'text/x-opml' => 'opml', + 'text/x-nfo' => 'nfo', + 'text/x-setext' => 'etx', + 'text/x-sfv' => 'sfv', + 'text/x-uuencode' => 'uu', + 'text/x-vcalendar' => 'vcs', + 'text/x-vcard' => 'vcf', + 'video/3gpp' => '3gp', + 'video/3gpp2' => '3g2', + 'video/h261' => 'h261', + 'video/h263' => 'h263', + 'video/h264' => 'h264', + 'video/jpeg' => 'jpgv', + 'video/jpm' => 'jpm', + 'video/mj2' => 'mj2', + 'video/mp4' => 'mp4', + 'video/mpeg' => 'mpeg', + 'video/ogg' => 'ogv', + 'video/quicktime' => 'qt', + 'video/vnd.dece.hd' => 'uvh', + 'video/vnd.dece.mobile' => 'uvm', + 'video/vnd.dece.pd' => 'uvp', + 'video/vnd.dece.sd' => 'uvs', + 'video/vnd.dece.video' => 'uvv', + 'video/vnd.dvb.file' => 'dvb', + 'video/vnd.fvt' => 'fvt', + 'video/vnd.mpegurl' => 'mxu', + 'video/vnd.ms-playready.media.pyv' => 'pyv', + 'video/vnd.uvvu.mp4' => 'uvu', + 'video/vnd.vivo' => 'viv', + 'video/webm' => 'webm', + 'video/x-f4v' => 'f4v', + 'video/x-fli' => 'fli', + 'video/x-flv' => 'flv', + 'video/x-m4v' => 'm4v', + 'video/x-matroska' => 'mkv', + 'video/x-mng' => 'mng', + 'video/x-ms-asf' => 'asf', + 'video/x-ms-vob' => 'vob', + 'video/x-ms-wm' => 'wm', + 'video/x-ms-wmv' => 'wmv', + 'video/x-ms-wmx' => 'wmx', + 'video/x-ms-wvx' => 'wvx', + 'video/x-msvideo' => 'avi', + 'video/x-sgi-movie' => 'movie', + 'video/x-smv' => 'smv', + 'x-conference/x-cooltalk' => 'ice', + ]; + + /** + * Reversed from $defaultExtensions property in constructor. + */ + private $defaultMineTypes = []; + + public function __construct() + { + $this->defaultMineTypes = array_flip($this->defaultExtensions); + } + + public function guessExtension(string $mimeType): ?string + { + return isset($this->defaultExtensions[$mimeType]) ? $this->defaultExtensions[$mimeType] : null; + } + + public function guessMimeType(string $extension): ?string + { + return isset($this->defaultMineTypes[$extension]) ? $this->defaultMineTypes[$extension] : null; + } +} From 2fae262076c8343f05c5750823ba57bb117afbd6 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Thu, 29 Aug 2019 16:19:15 +0800 Subject: [PATCH 158/225] Create FileException.php --- .../src/Exception/Http/FileException.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/http-server/src/Exception/Http/FileException.php diff --git a/src/http-server/src/Exception/Http/FileException.php b/src/http-server/src/Exception/Http/FileException.php new file mode 100644 index 000000000..172a4ea2e --- /dev/null +++ b/src/http-server/src/Exception/Http/FileException.php @@ -0,0 +1,19 @@ + Date: Thu, 29 Aug 2019 16:19:59 +0800 Subject: [PATCH 159/225] Optimized the etag algorithm and content-type --- .../src/Stream/SwooleFileStream.php | 16 +++-- src/http-server/src/Response.php | 70 +++++++++++++------ 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/http-message/src/Stream/SwooleFileStream.php b/src/http-message/src/Stream/SwooleFileStream.php index 042362630..fb5a9a93d 100644 --- a/src/http-message/src/Stream/SwooleFileStream.php +++ b/src/http-message/src/Stream/SwooleFileStream.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Hyperf\HttpMessage\Stream; +use Hyperf\HttpServer\Exception\Http\FileException; use InvalidArgumentException; use Psr\Http\Message\StreamInterface; @@ -30,15 +31,18 @@ class SwooleFileStream implements StreamInterface, FileInterface /** * SwooleFileStream constructor. * - * @param string $file + * @param string|\SplFileInfo $file */ - public function __construct(string $file) + public function __construct($file) { - if (! file_exists($file)) { - throw new InvalidArgumentException('Not a file'); + if (! $file instanceof \SplFileInfo) { + $file = new \SplFileInfo($file); } - $this->contents = $file; - $this->size = filesize($file); + if (! $file->isReadable()) { + throw new FileException('File must be readable.'); + } + $this->contents = $file->getPathname(); + $this->size = $file->getSize(); } /** diff --git a/src/http-server/src/Response.php b/src/http-server/src/Response.php index ce30debd4..0c478f9f8 100644 --- a/src/http-server/src/Response.php +++ b/src/http-server/src/Response.php @@ -17,7 +17,10 @@ use Hyperf\HttpMessage\Stream\SwooleFileStream; use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\HttpServer\Contract\ResponseInterface; use Hyperf\HttpServer\Exception\Http\EncodingException; +use Hyperf\HttpServer\Exception\Http\FileException; +use Hyperf\HttpServer\MimeType\MimeTypeExtensionGuesser; use Hyperf\Utils\ApplicationContext; +use Hyperf\Utils\ClearStatCache; use Hyperf\Utils\Context; use Hyperf\Utils\Contracts\Arrayable; use Hyperf\Utils\Contracts\Jsonable; @@ -25,6 +28,7 @@ use Hyperf\Utils\Contracts\Xmlable; use Hyperf\Utils\Str; use Hyperf\Utils\Traits\Macroable; use Psr\Http\Message\ResponseInterface as PsrResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamInterface; use SimpleXMLElement; use function get_class; @@ -111,20 +115,41 @@ class Response implements PsrResponseInterface, ResponseInterface return $this->getResponse()->withStatus($status)->withAddedHeader('Location', $toUrl); } - /** - * @param string $file - * @param string $name - * @return PsrResponseInterface - */ public function download(string $file, string $name = ''): PsrResponseInterface { - $filename = $name ?: basename($file); - return $this->withHeader('Content-Description', 'File Transfer') - ->withHeader('Content-Type', 'application/octet-stream') - ->withHeader('Content-Disposition', "attachment; filename={$filename}") - ->withHeader('Content-Transfer-Encoding', 'binary') - ->withHeader('Pragma', 'public') - ->withHeader('ETag', $this->etag($file)) + $file = new \SplFileInfo($file); + + if (! $file->isReadable()) { + throw new FileException('File must be readable.'); + } + + $filename = $name ?: $file->getBasename(); + $etag = $this->createEtag($file); + + // Determine if ETag the client expects matches calculated ETag + $request = Context::get(ServerRequestInterface::class); + if ($request instanceof ServerRequestInterface) { + $ifMatch = $request->getHeaderLine('if-match'); + $ifNoneMatch = $request->getHeaderLine('if-none-match'); + $clientEtags = explode(',', $ifMatch ?: $ifNoneMatch); + array_walk($clientEtags, 'trim'); + if (in_array($etag, $clientEtags, true)) { + return $this->withStatus(304); + } + } + + return $this->withHeader('content-description', 'File Transfer') + ->withHeader('content-type', value(function () use ($file) { + if (ApplicationContext::hasContainer()) { + $guesser = ApplicationContext::getContainer()->get(MimeTypeExtensionGuesser::class); + $mineType = $guesser->guessMimeType($file->getExtension()); + } + return $mineType ?? 'application/octet-stream'; + })) + ->withHeader('content-disposition', "attachment; filename={$filename}") + ->withHeader('content-transfer-encoding', 'binary') + ->withHeader('pragma', 'public') + ->withHeader('etag', $etag) ->withBody(new SwooleFileStream($file)); } @@ -364,17 +389,22 @@ class Response implements PsrResponseInterface, ResponseInterface /** * Get ETag header according to the checksum of the file. - * @param string $file - * @param bool $weak - * @return string */ - protected function etag(string $file, $weak = false): string + protected function createEtag(\SplFileInfo $file, bool $weak = false): string { - $etag = sha1_file($file); - if (strpos($etag, '"') !== 0) { - $etag = '"' . $etag . '"'; + $etag = ''; + if ($weak) { + ClearStatCache::clear($file->getPathname()); + $lastModified = $file->getMTime(); + $filesize = $file->getSize(); + if (! $lastModified || ! $filesize) { + return $etag; + } + $etag = sprintf('W/"%x-%x"', $lastModified, $filesize); + } else { + $etag = md5_file($file->getPathname()); } - return ($weak === true ? 'W/' : '') . $etag; + return $etag; } /** From d43cabb7ecd4e5f0c729f282f46c2f466f79c3be Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Thu, 29 Aug 2019 16:25:07 +0800 Subject: [PATCH 160/225] Optimized comment --- src/http-server/src/Contract/ResponseInterface.php | 5 ++++- src/http-server/src/Response.php | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/http-server/src/Contract/ResponseInterface.php b/src/http-server/src/Contract/ResponseInterface.php index 33ea6b293..98f3f88af 100644 --- a/src/http-server/src/Contract/ResponseInterface.php +++ b/src/http-server/src/Contract/ResponseInterface.php @@ -46,7 +46,10 @@ interface ResponseInterface public function redirect(string $toUrl, int $status = 302, string $schema = 'http'): PsrResponseInterface; /** - * Create a new file download response. + * Create a file download response. + * + * @param string $file The file path which want to send to client. + * @param string $name The alias name of the file that client receive. */ public function download(string $file, string $name = ''): PsrResponseInterface; } diff --git a/src/http-server/src/Response.php b/src/http-server/src/Response.php index 0c478f9f8..c895b33a0 100644 --- a/src/http-server/src/Response.php +++ b/src/http-server/src/Response.php @@ -115,6 +115,12 @@ class Response implements PsrResponseInterface, ResponseInterface return $this->getResponse()->withStatus($status)->withAddedHeader('Location', $toUrl); } + /** + * Create a file download response. + * + * @param string $file The file path which want to send to client. + * @param string $name The alias name of the file that client receive. + */ public function download(string $file, string $name = ''): PsrResponseInterface { $file = new \SplFileInfo($file); @@ -140,6 +146,7 @@ class Response implements PsrResponseInterface, ResponseInterface return $this->withHeader('content-description', 'File Transfer') ->withHeader('content-type', value(function () use ($file) { + $mineType = null; if (ApplicationContext::hasContainer()) { $guesser = ApplicationContext::getContainer()->get(MimeTypeExtensionGuesser::class); $mineType = $guesser->guessMimeType($file->getExtension()); From 6a24ed9184c2f9f7b9f9f6fa395b871b595b2a80 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Thu, 29 Aug 2019 16:26:51 +0800 Subject: [PATCH 161/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b9f328ea..aa0b34683 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd - [#420](https://github.com/hyperf-cloud/hyperf/pull/420) Added listener for model. - [#441](https://github.com/hyperf-cloud/hyperf/pull/441) Automatically close the spare redis client when it is used in low frequency. -- [#455](https://github.com/hyperf-cloud/hyperf/pull/455) Added download method for Response. +- [#455](https://github.com/hyperf-cloud/hyperf/pull/455) Added `download()` method of `Hyperf\HttpServer\Contract\ResponseInterface`. ## Changed From 28352f39fc4bff6595abcc5f27f9f73c8e745eb2 Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Thu, 29 Aug 2019 16:44:26 +0800 Subject: [PATCH 162/225] Remove $contents property --- src/http-message/src/Stream/SwooleFileStream.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/http-message/src/Stream/SwooleFileStream.php b/src/http-message/src/Stream/SwooleFileStream.php index fb5a9a93d..40a568e39 100644 --- a/src/http-message/src/Stream/SwooleFileStream.php +++ b/src/http-message/src/Stream/SwooleFileStream.php @@ -13,7 +13,6 @@ declare(strict_types=1); namespace Hyperf\HttpMessage\Stream; use Hyperf\HttpServer\Exception\Http\FileException; -use InvalidArgumentException; use Psr\Http\Message\StreamInterface; class SwooleFileStream implements StreamInterface, FileInterface @@ -21,12 +20,12 @@ class SwooleFileStream implements StreamInterface, FileInterface /** * @var string */ - protected $contents; + protected $size; /** - * @var string + * @var \SplFileInfo */ - protected $size; + protected $file; /** * SwooleFileStream constructor. @@ -41,7 +40,7 @@ class SwooleFileStream implements StreamInterface, FileInterface if (! $file->isReadable()) { throw new FileException('File must be readable.'); } - $this->contents = $file->getPathname(); + $this->file = $file; $this->size = $file->getSize(); } @@ -236,6 +235,6 @@ class SwooleFileStream implements StreamInterface, FileInterface public function getFilename(): string { - return $this->getContents(); + return $this->file->getPathname(); } } From 2c48d97859d9c979464c6699d7103a2cacd9995f Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Thu, 29 Aug 2019 16:44:50 +0800 Subject: [PATCH 163/225] Add content-type even return 304 --- src/http-server/src/Response.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/http-server/src/Response.php b/src/http-server/src/Response.php index c895b33a0..719a28b19 100644 --- a/src/http-server/src/Response.php +++ b/src/http-server/src/Response.php @@ -131,6 +131,14 @@ class Response implements PsrResponseInterface, ResponseInterface $filename = $name ?: $file->getBasename(); $etag = $this->createEtag($file); + $contentType = value(function () use ($file) { + $mineType = null; + if (ApplicationContext::hasContainer()) { + $guesser = ApplicationContext::getContainer()->get(MimeTypeExtensionGuesser::class); + $mineType = $guesser->guessMimeType($file->getExtension()); + } + return $mineType ?? 'application/octet-stream'; + }); // Determine if ETag the client expects matches calculated ETag $request = Context::get(ServerRequestInterface::class); @@ -140,19 +148,12 @@ class Response implements PsrResponseInterface, ResponseInterface $clientEtags = explode(',', $ifMatch ?: $ifNoneMatch); array_walk($clientEtags, 'trim'); if (in_array($etag, $clientEtags, true)) { - return $this->withStatus(304); + return $this->withStatus(304)->withAddedHeader('content-type', $contentType); } } return $this->withHeader('content-description', 'File Transfer') - ->withHeader('content-type', value(function () use ($file) { - $mineType = null; - if (ApplicationContext::hasContainer()) { - $guesser = ApplicationContext::getContainer()->get(MimeTypeExtensionGuesser::class); - $mineType = $guesser->guessMimeType($file->getExtension()); - } - return $mineType ?? 'application/octet-stream'; - })) + ->withHeader('content-type', $contentType) ->withHeader('content-disposition', "attachment; filename={$filename}") ->withHeader('content-transfer-encoding', 'binary') ->withHeader('pragma', 'public') From 79d6a07f766a1e84663d4d212e29aaef7064b65d Mon Sep 17 00:00:00 2001 From: huangzhhui Date: Thu, 29 Aug 2019 16:49:30 +0800 Subject: [PATCH 164/225] Update response.md --- doc/zh/response.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/doc/zh/response.md b/doc/zh/response.md index abf5897bf..0e9615eda 100644 --- a/doc/zh/response.md +++ b/doc/zh/response.md @@ -125,20 +125,31 @@ class IndexController ## 分块传输编码 Chunk -## 返回文件下载 +## 文件下载 + +`Hyperf\HttpServer\Contract\ResponseInterface` 提供了 `download(string $file, string $name = '')` 返回一个已设置下载文件状态的 `Psr7ResponseInterface` 对象。 +如果请求中带有 `if-match` 或 `if-none-match` 的请求头,Hyperf 也会跟根据协议标准与 `ETag` 进行比较,如果一致则会返回一个 `304` 状态码的响应。 + +`download` 方法: + +| 参数 | 类型 | 默认值 | 备注 | +|:-------------------:|:------:|:---------------:|:------------------:| +| file | string | 无 | 要返回下载文件的绝对路径,同通过 BASE_PATH 常量来定位到项目的根目录 | +| name | string | 无 | 客户端下载文件的文件名,为空则会使用下载文件的原名 | + + ```php download('/var/www/file.csv','filename.csv'); + return $response->download(BASE_PATH . '/public/file.csv', 'filename.csv'); } } ``` \ No newline at end of file From 6719f7b07029ddfcbec278483b47a0a4ff80d808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 29 Aug 2019 17:20:22 +0800 Subject: [PATCH 165/225] Update response.md --- doc/zh/response.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/zh/response.md b/doc/zh/response.md index 0e9615eda..09fed43a1 100644 --- a/doc/zh/response.md +++ b/doc/zh/response.md @@ -78,11 +78,11 @@ class IndexController `redirect` 方法: -| 参数 | 类型 | 默认值 | 备注 | -|:-------------------:|:------:|:---------------:|:------------------:| -| toUrl | string | 无 | 如果参数不存在 `http://` 或 `https://` 则根据当前服务的 Host 自动拼接对应的 URL,且根据 `$schema` 参数拼接协议 | -| status | int | 302 | 响应状态码 | -| schema | string | http | 当 `$toUrl` 不存在 `http://` 或 `https://` 时生效,仅可传递 `http` 或 `https` | +| 参数 | 类型 | 默认值 | 备注 | +|:------:|:------:|:------:|:--------------------------------------------------------------------------------------------------------------:| +| toUrl | string | 无 | 如果参数不存在 `http://` 或 `https://` 则根据当前服务的 Host 自动拼接对应的 URL,且根据 `$schema` 参数拼接协议 | +| status | int | 302 | 响应状态码 | +| schema | string | http | 当 `$toUrl` 不存在 `http://` 或 `https://` 时生效,仅可传递 `http` 或 `https` | ```php Date: Thu, 29 Aug 2019 18:45:41 +0800 Subject: [PATCH 166/225] Moved MimeTypeExtensionGuesser to Utils --- src/http-server/src/Response.php | 2 +- .../src/MimeType => utils/src}/MimeTypeExtensionGuesser.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{http-server/src/MimeType => utils/src}/MimeTypeExtensionGuesser.php (99%) diff --git a/src/http-server/src/Response.php b/src/http-server/src/Response.php index 719a28b19..28939064f 100644 --- a/src/http-server/src/Response.php +++ b/src/http-server/src/Response.php @@ -18,7 +18,7 @@ use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\HttpServer\Contract\ResponseInterface; use Hyperf\HttpServer\Exception\Http\EncodingException; use Hyperf\HttpServer\Exception\Http\FileException; -use Hyperf\HttpServer\MimeType\MimeTypeExtensionGuesser; +use Hyperf\Utils\MimeTypeExtensionGuesser; use Hyperf\Utils\ApplicationContext; use Hyperf\Utils\ClearStatCache; use Hyperf\Utils\Context; diff --git a/src/http-server/src/MimeType/MimeTypeExtensionGuesser.php b/src/utils/src/MimeTypeExtensionGuesser.php similarity index 99% rename from src/http-server/src/MimeType/MimeTypeExtensionGuesser.php rename to src/utils/src/MimeTypeExtensionGuesser.php index 2f79c0b7c..57ee4f414 100644 --- a/src/http-server/src/MimeType/MimeTypeExtensionGuesser.php +++ b/src/utils/src/MimeTypeExtensionGuesser.php @@ -10,7 +10,7 @@ declare(strict_types=1); * @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE */ -namespace Hyperf\HttpServer\MimeType; +namespace Hyperf\Utils; class MimeTypeExtensionGuesser { From aefff23d0388ca8435f4a464f415df2867f43712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 30 Aug 2019 10:56:32 +0800 Subject: [PATCH 167/225] Fixed `getParsedBody` not deserialize json contents. --- src/http-message/.gitattributes | 1 + src/http-message/src/Server/Request.php | 24 +++++-- .../src/Stream/SwooleFileStream.php | 2 +- src/http-message/tests/ServerRequestTest.php | 62 +++++++++++++++++++ .../tests/Stub/Server/RequestStub.php | 24 +++++++ 5 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 src/http-message/.gitattributes create mode 100644 src/http-message/tests/ServerRequestTest.php create mode 100644 src/http-message/tests/Stub/Server/RequestStub.php diff --git a/src/http-message/.gitattributes b/src/http-message/.gitattributes new file mode 100644 index 000000000..bdd4ea29c --- /dev/null +++ b/src/http-message/.gitattributes @@ -0,0 +1 @@ +/tests export-ignore \ No newline at end of file diff --git a/src/http-message/src/Server/Request.php b/src/http-message/src/Server/Request.php index fbab9013d..b6b2367b1 100755 --- a/src/http-message/src/Server/Request.php +++ b/src/http-message/src/Server/Request.php @@ -15,6 +15,7 @@ namespace Hyperf\HttpMessage\Server; use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\HttpMessage\Upload\UploadedFile; use Hyperf\HttpMessage\Uri\Uri; +use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\UploadedFileInterface; @@ -80,7 +81,7 @@ class Request extends \Hyperf\HttpMessage\Base\Request implements ServerRequestI $request->cookieParams = ($swooleRequest->cookie ?? []); $request->queryParams = ($swooleRequest->get ?? []); $request->serverParams = ($server ?? []); - $request->parsedBody = ($swooleRequest->post ?? []); + $request->parsedBody = self::normalizeParsedBody($swooleRequest->post ?? [], $request); $request->uploadedFiles = self::normalizeFiles($swooleRequest->files ?? []); $request->swooleRequest = $swooleRequest; return $request; @@ -349,10 +350,10 @@ class Request extends \Hyperf\HttpMessage\Base\Request implements ServerRequestI * This method obviates the need for a hasAttribute() method, as it allows * specifying a default value to return if the attribute is not found. * - * @see getAttributes() * @param string $name the attribute name * @param mixed $default default value to return if the attribute does not exist * @return mixed + * @see getAttributes() */ public function getAttribute($name, $default = null) { @@ -367,10 +368,10 @@ class Request extends \Hyperf\HttpMessage\Base\Request implements ServerRequestI * immutability of the message, and MUST return an instance that has the * updated attribute. * - * @see getAttributes() * @param string $name the attribute name * @param mixed $value the value of the attribute * @return static + * @see getAttributes() */ public function withAttribute($name, $value) { @@ -387,9 +388,9 @@ class Request extends \Hyperf\HttpMessage\Base\Request implements ServerRequestI * immutability of the message, and MUST return an instance that removes * the attribute. * - * @see getAttributes() * @param string $name the attribute name * @return static + * @see getAttributes() */ public function withoutAttribute($name) { @@ -468,6 +469,21 @@ class Request extends \Hyperf\HttpMessage\Base\Request implements ServerRequestI return $this; } + protected static function normalizeParsedBody(array $data = [], ?RequestInterface $request = null) + { + if (! $request) { + return $data; + } + + $method = strtolower($request->getMethod()); + $contentType = strtolower($request->getHeaderLine('Content-Type')); + if ($method == 'post' && strpos($contentType, 'application/json') === 0) { + $data = json_decode($request->getBody()->getContents(), true) ?? []; + } + + return $data; + } + /** * Return an UploadedFile instance array. * diff --git a/src/http-message/src/Stream/SwooleFileStream.php b/src/http-message/src/Stream/SwooleFileStream.php index 40a568e39..35d69e37b 100644 --- a/src/http-message/src/Stream/SwooleFileStream.php +++ b/src/http-message/src/Stream/SwooleFileStream.php @@ -30,7 +30,7 @@ class SwooleFileStream implements StreamInterface, FileInterface /** * SwooleFileStream constructor. * - * @param string|\SplFileInfo $file + * @param \SplFileInfo|string $file */ public function __construct($file) { diff --git a/src/http-message/tests/ServerRequestTest.php b/src/http-message/tests/ServerRequestTest.php new file mode 100644 index 000000000..431445739 --- /dev/null +++ b/src/http-message/tests/ServerRequestTest.php @@ -0,0 +1,62 @@ + 1]; + $json = ['name' => 'Hyperf']; + + $request = Mockery::mock(RequestInterface::class); + $request->shouldReceive('getMethod')->andReturn('GET'); + $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn(''); + + $this->assertSame($data, RequestStub::normalizeParsedBody($data)); + $this->assertSame($data, RequestStub::normalizeParsedBody($data, $request)); + + $request = Mockery::mock(RequestInterface::class); + $request->shouldReceive('getMethod')->andReturn('POST'); + $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/xml'); + $this->assertSame($data, RequestStub::normalizeParsedBody($data, $request)); + + $request = Mockery::mock(RequestInterface::class); + $request->shouldReceive('getMethod')->andReturn('POST'); + $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/json; charset=utf-8'); + $request->shouldReceive('getBody')->andReturn(new SwooleStream(json_encode($json))); + $this->assertSame($json, RequestStub::normalizeParsedBody($data, $request)); + + $request = Mockery::mock(RequestInterface::class); + $request->shouldReceive('getMethod')->andReturn('POST'); + $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/JSON'); + $request->shouldReceive('getBody')->andReturn(new SwooleStream(json_encode($json))); + $this->assertSame($json, RequestStub::normalizeParsedBody($data, $request)); + + $request = Mockery::mock(RequestInterface::class); + $request->shouldReceive('getMethod')->andReturn('POST'); + $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/json; charset=utf-8'); + $request->shouldReceive('getBody')->andReturn(new SwooleStream('xxxx')); + $this->assertSame([], RequestStub::normalizeParsedBody($data, $request)); + } +} diff --git a/src/http-message/tests/Stub/Server/RequestStub.php b/src/http-message/tests/Stub/Server/RequestStub.php new file mode 100644 index 000000000..0b8d8a600 --- /dev/null +++ b/src/http-message/tests/Stub/Server/RequestStub.php @@ -0,0 +1,24 @@ + Date: Fri, 30 Aug 2019 11:01:23 +0800 Subject: [PATCH 168/225] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa0b34683..93717f457 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ## Changed - [#437](https://github.com/hyperf-cloud/hyperf/pull/437) Changed `Hyperf\Testing\Client` handle exception handlers instead of throw an exception directly. +- [#486](https://github.com/hyperf-cloud/hyperf/pull/486) Changed `getParsedBody` can return JSON formatted data normally. ## Deleted From 8602818f009cd5ff537629f0a048a56bd580289a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 30 Aug 2019 11:04:35 +0800 Subject: [PATCH 169/225] Not only post method. --- src/http-message/src/Server/Request.php | 3 +-- src/http-message/tests/ServerRequestTest.php | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/http-message/src/Server/Request.php b/src/http-message/src/Server/Request.php index b6b2367b1..bd9a0f605 100755 --- a/src/http-message/src/Server/Request.php +++ b/src/http-message/src/Server/Request.php @@ -475,9 +475,8 @@ class Request extends \Hyperf\HttpMessage\Base\Request implements ServerRequestI return $data; } - $method = strtolower($request->getMethod()); $contentType = strtolower($request->getHeaderLine('Content-Type')); - if ($method == 'post' && strpos($contentType, 'application/json') === 0) { + if (strpos($contentType, 'application/json') === 0) { $data = json_decode($request->getBody()->getContents(), true) ?? []; } diff --git a/src/http-message/tests/ServerRequestTest.php b/src/http-message/tests/ServerRequestTest.php index 431445739..791c2c647 100644 --- a/src/http-message/tests/ServerRequestTest.php +++ b/src/http-message/tests/ServerRequestTest.php @@ -30,31 +30,26 @@ class ServerRequestTest extends TestCase $json = ['name' => 'Hyperf']; $request = Mockery::mock(RequestInterface::class); - $request->shouldReceive('getMethod')->andReturn('GET'); $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn(''); $this->assertSame($data, RequestStub::normalizeParsedBody($data)); $this->assertSame($data, RequestStub::normalizeParsedBody($data, $request)); $request = Mockery::mock(RequestInterface::class); - $request->shouldReceive('getMethod')->andReturn('POST'); $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/xml'); $this->assertSame($data, RequestStub::normalizeParsedBody($data, $request)); $request = Mockery::mock(RequestInterface::class); - $request->shouldReceive('getMethod')->andReturn('POST'); $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/json; charset=utf-8'); $request->shouldReceive('getBody')->andReturn(new SwooleStream(json_encode($json))); $this->assertSame($json, RequestStub::normalizeParsedBody($data, $request)); $request = Mockery::mock(RequestInterface::class); - $request->shouldReceive('getMethod')->andReturn('POST'); $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/JSON'); $request->shouldReceive('getBody')->andReturn(new SwooleStream(json_encode($json))); $this->assertSame($json, RequestStub::normalizeParsedBody($data, $request)); $request = Mockery::mock(RequestInterface::class); - $request->shouldReceive('getMethod')->andReturn('POST'); $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/json; charset=utf-8'); $request->shouldReceive('getBody')->andReturn(new SwooleStream('xxxx')); $this->assertSame([], RequestStub::normalizeParsedBody($data, $request)); From 25e3f3c96bba40ff6adcc100bd3b83a8e67ec000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 30 Aug 2019 11:14:02 +0800 Subject: [PATCH 170/225] Update Request.php --- src/http-server/src/Request.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/http-server/src/Request.php b/src/http-server/src/Request.php index f1864aad7..abc5017e7 100644 --- a/src/http-server/src/Request.php +++ b/src/http-server/src/Request.php @@ -564,11 +564,7 @@ class Request implements RequestInterface { return $this->storeParsedData(function () { $request = $this->getRequest(); - $contentType = $request->getHeaderLine('Content-Type'); - if ($contentType && Str::startsWith($contentType, 'application/json')) { - $body = $request->getBody(); - $data = json_decode($body->getContents(), true) ?? []; - } elseif (is_array($request->getParsedBody())) { + if (is_array($request->getParsedBody())) { $data = $request->getParsedBody(); } else { $data = []; From a1548ff30ddc02b8a610945bb3ec8a1b99cc071e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 30 Aug 2019 14:02:24 +0800 Subject: [PATCH 171/225] Update ServerRequestTest.php --- src/http-message/tests/ServerRequestTest.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/http-message/tests/ServerRequestTest.php b/src/http-message/tests/ServerRequestTest.php index 791c2c647..2e22973ef 100644 --- a/src/http-message/tests/ServerRequestTest.php +++ b/src/http-message/tests/ServerRequestTest.php @@ -44,14 +44,20 @@ class ServerRequestTest extends TestCase $request->shouldReceive('getBody')->andReturn(new SwooleStream(json_encode($json))); $this->assertSame($json, RequestStub::normalizeParsedBody($data, $request)); - $request = Mockery::mock(RequestInterface::class); - $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/JSON'); - $request->shouldReceive('getBody')->andReturn(new SwooleStream(json_encode($json))); - $this->assertSame($json, RequestStub::normalizeParsedBody($data, $request)); - $request = Mockery::mock(RequestInterface::class); $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/json; charset=utf-8'); $request->shouldReceive('getBody')->andReturn(new SwooleStream('xxxx')); $this->assertSame([], RequestStub::normalizeParsedBody($data, $request)); } + + public function testNormalizeParsedBodyInvalidContentType() + { + $data = ['id' => 1]; + $json = ['name' => 'Hyperf']; + + $request = Mockery::mock(RequestInterface::class); + $request->shouldReceive('getHeaderLine')->with('Content-Type')->andReturn('application/JSON'); + $request->shouldReceive('getBody')->andReturn(new SwooleStream(json_encode($json))); + $this->assertSame($json, RequestStub::normalizeParsedBody($data, $request)); + } } From 77c7d71046ad447374a1577851b18f04463eea52 Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Fri, 30 Aug 2019 16:32:43 +0800 Subject: [PATCH 172/225] Update swoole-tracker.md --- doc/zh/swoole-tracker.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/doc/zh/swoole-tracker.md b/doc/zh/swoole-tracker.md index 4a94bb595..fa8f45bd9 100644 --- a/doc/zh/swoole-tracker.md +++ b/doc/zh/swoole-tracker.md @@ -113,15 +113,26 @@ EXPOSE 9501 ENTRYPOINT ["sh", ".build/entrypoint.sh"] ``` -### 安装组件 + +## 使用 + +### 不依赖组件 + +`Swoole Tracker`的`v2.5.0`版本支持自动生成应用名称并创建应用,无需修改任何代码,生成的应用名称格式为: + +`Swoole`的`HttpServer`:`ip:prot` + +其他的`Server`:`ip(hostname):prot` + +### 依赖组件 + +当你需要自定义应用名称时则需要安装组件,使用`Composer`安装: ```bash composer require hyperf/swoole-tracker ``` -## 使用 - -在 `config/autoload/middlewares.php` 配置文件中注册 `Hyperf\SwooleTracker\Middleware\HttpServerMiddleware` 中间件即可,如下: +安装完成后在 `config/autoload/middlewares.php` 配置文件中注册 `Hyperf\SwooleTracker\Middleware\HttpServerMiddleware` 中间件即可,如下: ```php Date: Fri, 30 Aug 2019 16:34:16 +0800 Subject: [PATCH 173/225] Update composer.json --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index b8b5df5fc..f353993f3 100644 --- a/composer.json +++ b/composer.json @@ -153,7 +153,7 @@ "Hyperf\\ServiceGovernance\\": "src/service-governance/src/", "Hyperf\\Snowflake\\": "src/snowflake/src/", "Hyperf\\Swagger\\": "src/swagger/src/", - "Hyperf\\SwooleEnterprise\\": "src/swoole-enterprise/src/", + "Hyperf\\SwooleTracker\\": "src/swoole-tracker/src/", "Hyperf\\Task\\": "src/task/src/", "Hyperf\\Testing\\": "src/testing/src/", "Hyperf\\Tracer\\": "src/tracer/src/", @@ -250,7 +250,7 @@ "Hyperf\\ServiceGovernance\\ConfigProvider", "Hyperf\\Snowflake\\ConfigProvider", "Hyperf\\Swagger\\ConfigProvider", - "Hyperf\\SwooleEnterprise\\ConfigProvider", + "Hyperf\\SwooleTracker\\ConfigProvider", "Hyperf\\Task\\ConfigProvider", "Hyperf\\Tracer\\ConfigProvider", "Hyperf\\Utils\\ConfigProvider", @@ -270,4 +270,4 @@ }, "minimum-stability": "dev", "prefer-stable": true -} \ No newline at end of file +} From 08787b92a63ad5be5712a7dab636f8effd2e47ce Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Fri, 30 Aug 2019 17:04:26 +0800 Subject: [PATCH 174/225] Update swoole-tracker.md --- doc/zh/swoole-tracker.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/zh/swoole-tracker.md b/doc/zh/swoole-tracker.md index fa8f45bd9..dce14eb80 100644 --- a/doc/zh/swoole-tracker.md +++ b/doc/zh/swoole-tracker.md @@ -113,7 +113,6 @@ EXPOSE 9501 ENTRYPOINT ["sh", ".build/entrypoint.sh"] ``` - ## 使用 ### 不依赖组件 @@ -124,6 +123,8 @@ ENTRYPOINT ["sh", ".build/entrypoint.sh"] 其他的`Server`:`ip(hostname):prot` +即安装好`swoole_tracker`扩展之后就可以正常使用`Swoole Tracker`的功能 + ### 依赖组件 当你需要自定义应用名称时则需要安装组件,使用`Composer`安装: From 7bccbcd845aa0381243b8dd6c799dee8b7e3471e Mon Sep 17 00:00:00 2001 From: linchunbo Date: Fri, 30 Aug 2019 18:03:01 +0800 Subject: [PATCH 175/225] =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E5=99=A8=E7=AB=A0=E8=8A=82=E4=B8=8B=E9=9D=A2?= =?UTF-8?q?=E3=80=90=E9=81=BF=E5=85=8D=E5=8D=8F=E7=A8=8B=E9=97=B4=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=B7=B7=E6=B7=86=E3=80=91=E6=AE=B5=E8=90=BD=E9=94=99?= =?UTF-8?q?=E5=88=AB=E5=AD=97=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/zh/controller.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/controller.md b/doc/zh/controller.md index 2a59e70fd..726759eeb 100644 --- a/doc/zh/controller.md +++ b/doc/zh/controller.md @@ -37,6 +37,6 @@ Hello Hyperf. ## 避免协程间数据混淆 -在传统的 PHP-FPM 的框架里,会习惯提供一个 `AbstractController` 或其它命名的 `Controller 抽象父类`,然后定义的 `Controller` 需要基础它用于获取一些请求数据或进行一些返回操作,在 Hyperf 里是 **不能这样做** 的,因为在 Hyperf 内绝大部分的对象包括 `Controller` 都是以 `单例(Singleton)` 形式存在的,这也是为了更好的复用对象,而对于与请求相关的数据在协程下也是需要储存到 `协程上下文(Context)` 内的,所以在编写代码时请务必注意 **不要** 将单个请求相关的数据储存在类属性内,包括非静态属性。 +在传统的 PHP-FPM 的框架里,会习惯提供一个 `AbstractController` 或其它命名的 `Controller 抽象父类`,然后定义的 `Controller` 需要继承它用于获取一些请求数据或进行一些返回操作,在 Hyperf 里是 **不能这样做** 的,因为在 Hyperf 内绝大部分的对象包括 `Controller` 都是以 `单例(Singleton)` 形式存在的,这也是为了更好的复用对象,而对于与请求相关的数据在协程下也是需要储存到 `协程上下文(Context)` 内的,所以在编写代码时请务必注意 **不要** 将单个请求相关的数据储存在类属性内,包括非静态属性。 当然如果非要通过类属性来储存请求数据的话,也不是没有办法的,我们可以注意到我们获取 `请求(Request)` 与 `响应(Response)` 对象时是通过注入 `Hyperf\HttpServer\Contract\RequestInterface` 和 `Hyperf\HttpServer\Contract\ResponseInterface` 来获取的,那对应的对象不也是个单例吗?这里是如何做到协程安全的呢?就 `RequestInterface` 来举例,对应的 `Hyperf\HttpServer\Request` 对象内部在获取 `PSR-7 请求对象` 时,都是从 `协程上下文(Context)` 获取的,所以实际使用的类仅仅是一个代理类,实际调用的都是从 `协程上下文(Context)` 中获取的。 \ No newline at end of file From 5ec65b64cf1fd0a4d7c93bc5b1ed1eac686bceca Mon Sep 17 00:00:00 2001 From: hedeqiang Date: Sat, 31 Aug 2019 15:00:59 +0800 Subject: [PATCH 176/225] Update paginator.md --- doc/zh/paginator.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/doc/zh/paginator.md b/doc/zh/paginator.md index a55f51708..32c740d8f 100644 --- a/doc/zh/paginator.md +++ b/doc/zh/paginator.md @@ -97,4 +97,39 @@ $previousPageUrl = $paginator->previousPageUrl(); url($page); +``` + +## 获取当前页页码 + +```php +currentPage(); +``` + +## 当前页是否为第一页 + +```php +onFirstPage(); +``` + +## 是否有多页 + +```php +hasMorePages(); +``` + +## 每页的数据条数 + +```php +perPage(); +``` + +## 数据总数 + +```php +total(); ``` \ No newline at end of file From f88cd803a5819076ec775e972c9e97370810a160 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Sun, 1 Sep 2019 11:10:37 +0800 Subject: [PATCH 177/225] add swoole-tracker new file: swoole-tracker/LICENSE.md new file: swoole-tracker/README.md new file: swoole-tracker/composer.json new file: swoole-tracker/src/ConfigProvider.php new file: swoole-tracker/src/Middleware/HttpServerMiddleware.php --- src/swoole-tracker/LICENSE.md | 9 +++ src/swoole-tracker/README.md | 31 ++++++++++ src/swoole-tracker/composer.json | 56 +++++++++++++++++++ src/swoole-tracker/src/ConfigProvider.php | 31 ++++++++++ .../src/Middleware/HttpServerMiddleware.php | 54 ++++++++++++++++++ 5 files changed, 181 insertions(+) create mode 100644 src/swoole-tracker/LICENSE.md create mode 100644 src/swoole-tracker/README.md create mode 100644 src/swoole-tracker/composer.json create mode 100644 src/swoole-tracker/src/ConfigProvider.php create mode 100644 src/swoole-tracker/src/Middleware/HttpServerMiddleware.php diff --git a/src/swoole-tracker/LICENSE.md b/src/swoole-tracker/LICENSE.md new file mode 100644 index 000000000..eb14702a3 --- /dev/null +++ b/src/swoole-tracker/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) Hyperf + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/swoole-tracker/README.md b/src/swoole-tracker/README.md new file mode 100644 index 000000000..ed1d2a86b --- /dev/null +++ b/src/swoole-tracker/README.md @@ -0,0 +1,31 @@ +# Swoole Tracker + +[Swoole Tracker](https://www.swoole-cloud.com/tracker.html)作为`Swoole`官方出品的一整套企业级`PHP`和`Swoole`分析调试工具,更专一、更专业。 + +* 时刻掌握应用架构模型 + +> 自动发现应用依赖拓扑结构和展示,时刻掌握应用的架构模型 + +* 分布式跨应用链路追踪 + +> 支持无侵入的分布式跨应用链路追踪,让每个请求一目了然,全面支持协程/非协程环境,数据实时可视化 + +* 全面分析报告服务状况 + +> 各种维度统计服务上报的调用信息, 比如总流量、平均耗时、超时率等,并全面分析报告服务状况 + +* 拥有强大的调试工具链 + +> 本系统支持远程调试,可在系统后台远程开启检测内存泄漏、阻塞检测和代码性能分析 + +* 同时支持FPM和Swoole + +> 完美支持PHP-FPM环境,不仅限于在Swoole中使用 + +* 完善的系统监控 + +> 支持完善的系统监控,零成本部署,监控机器的CPU、内存、网络、磁盘等资源,可以很方便的集成到现有报警系统 + +* 零成本接入系统 + +> 本系统的客户端提供脚本可一键部署,服务端可在Docker环境中运行,简单快捷 diff --git a/src/swoole-tracker/composer.json b/src/swoole-tracker/composer.json new file mode 100644 index 000000000..6b65d3971 --- /dev/null +++ b/src/swoole-tracker/composer.json @@ -0,0 +1,56 @@ +{ + "name": "hyperf/swoole-tracker", + "description": "A swoole tracker library for Hyperf.", + "license": "MIT", + "keywords": [ + "php", + "swoole", + "hyperf", + "swoole-tracker" + ], + "support": { + }, + "require": { + "php": ">=7.2", + "ext-swoole": ">=4.3", + "hyperf/contract": "~1.1.0", + "hyperf/utils": "~1.1.0", + "psr/container": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.9", + "malukenho/docheader": "^0.1.6", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.0" + }, + "suggest": { + }, + "autoload": { + "psr-4": { + "Hyperf\\SwooleTracker\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + } + }, + "config": { + "sort-packages": true + }, + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + }, + "hyperf": { + "config": "Hyperf\\SwooleTracker\\ConfigProvider" + } + }, + "bin": [ + ], + "scripts": { + "cs-fix": "php-cs-fixer fix $1", + "test": "phpunit --colors=always" + } +} diff --git a/src/swoole-tracker/src/ConfigProvider.php b/src/swoole-tracker/src/ConfigProvider.php new file mode 100644 index 000000000..31ebb7e16 --- /dev/null +++ b/src/swoole-tracker/src/ConfigProvider.php @@ -0,0 +1,31 @@ + [ + ], + 'commands' => [ + ], + 'scan' => [ + 'paths' => [ + __DIR__, + ], + ], + ]; + } +} diff --git a/src/swoole-tracker/src/Middleware/HttpServerMiddleware.php b/src/swoole-tracker/src/Middleware/HttpServerMiddleware.php new file mode 100644 index 000000000..92dfd7061 --- /dev/null +++ b/src/swoole-tracker/src/Middleware/HttpServerMiddleware.php @@ -0,0 +1,54 @@ +name = $config->get('app_name', 'hyperf-skeleton'); + } + + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + if (class_exists(Stats::class)) { + $path = $request->getUri()->getPath(); + $ip = current(swoole_get_local_ip()); + + $tick = Stats::beforeExecRpc($path, $this->name, $ip); + try { + $response = $handler->handle($request); + Stats::afterExecRpc($tick, true, $response->getStatusCode()); + } catch (\Throwable $exception) { + Stats::afterExecRpc($tick, false, $exception->getCode()); + throw $exception; + } + } else { + $response = $handler->handle($request); + } + + return $response; + } +} From df582478e9b476319cf7e4deb2e163f973dda697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Sun, 1 Sep 2019 16:16:27 +0800 Subject: [PATCH 178/225] Update paginator.md --- doc/zh/paginator.md | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/doc/zh/paginator.md b/doc/zh/paginator.md index 32c740d8f..77b99d956 100644 --- a/doc/zh/paginator.md +++ b/doc/zh/paginator.md @@ -81,7 +81,7 @@ if ($paginator->hasMorePages()) { } ``` -## 获取上一页和下一页的 URL +## 获取对应分页的 URL ```php hasMorePages()) { $nextPageUrl = $paginator->nextPageUrl(); // 上一页的 URL $previousPageUrl = $paginator->previousPageUrl(); -``` - -## 获取指定页数的 URL - -```php -url($page); ``` -## 获取当前页页码 - -```php -currentPage(); -``` - -## 当前页是否为第一页 +## 是否处于第一页 ```php onFirstPage(); ``` -## 是否有多页 +## 是否有更多分页 ```php perPage(); ```php total(); -``` \ No newline at end of file +``` From 6acf4bc3d42a6696614f747fa94046e18ace789a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 1 Sep 2019 18:42:56 +0800 Subject: [PATCH 179/225] Added header and cookie. --- .../src/Contract/ResponseInterface.php | 17 +++++++- .../Http/InvalidResponseException.php | 19 +++++++++ src/http-server/src/Response.php | 33 +++++++++++++-- src/http-server/tests/ResponseTest.php | 42 +++++++++++++++++++ 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 src/http-server/src/Exception/Http/InvalidResponseException.php diff --git a/src/http-server/src/Contract/ResponseInterface.php b/src/http-server/src/Contract/ResponseInterface.php index 98f3f88af..e1810ae15 100644 --- a/src/http-server/src/Contract/ResponseInterface.php +++ b/src/http-server/src/Contract/ResponseInterface.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Hyperf\HttpServer\Contract; +use Hyperf\HttpMessage\Cookie\Cookie; use Hyperf\Utils\Contracts\Arrayable; use Hyperf\Utils\Contracts\Jsonable; use Hyperf\Utils\Contracts\Xmlable; @@ -48,8 +49,20 @@ interface ResponseInterface /** * Create a file download response. * - * @param string $file The file path which want to send to client. - * @param string $name The alias name of the file that client receive. + * @param string $file the file path which want to send to client + * @param string $name the alias name of the file that client receive */ public function download(string $file, string $name = ''): PsrResponseInterface; + + /** + * Override a response with a cookie. + */ + public function cookie(Cookie $cookie): ResponseInterface; + + /** + * Override a response with a header. + * + * @param string|string[] $value + */ + public function header(string $name, $value): ResponseInterface; } diff --git a/src/http-server/src/Exception/Http/InvalidResponseException.php b/src/http-server/src/Exception/Http/InvalidResponseException.php new file mode 100644 index 000000000..75b40c93c --- /dev/null +++ b/src/http-server/src/Exception/Http/InvalidResponseException.php @@ -0,0 +1,19 @@ +withBody(new SwooleFileStream($file)); } + public function cookie(Cookie $cookie): ResponseInterface + { + Context::override(PsrResponseInterface::class, function ($response) use ($cookie) { + if (! $response instanceof ServerResponse) { + throw new InvalidResponseException('The response is not instanceof ' . ServerResponse::class); + } + return $response->withCookie($cookie); + }); + + return $this; + } + + public function header(string $name, $value): ResponseInterface + { + Context::override(PsrResponseInterface::class, function ($response) use ($name, $value) { + if (! $response instanceof PsrResponseInterface) { + throw new InvalidResponseException('The response is not instanceof ' . PsrResponseInterface::class); + } + return $response->withHeader($name, $value); + }); + + return $this; + } + /** * Retrieves the HTTP protocol version as a string. * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0"). diff --git a/src/http-server/tests/ResponseTest.php b/src/http-server/tests/ResponseTest.php index c6ef470fd..ed26ace40 100644 --- a/src/http-server/tests/ResponseTest.php +++ b/src/http-server/tests/ResponseTest.php @@ -12,7 +12,9 @@ declare(strict_types=1); namespace HyperfTest\HttpServer; +use Hyperf\HttpMessage\Cookie\Cookie; use Hyperf\HttpMessage\Stream\SwooleStream; +use Hyperf\HttpServer\Contract\ResponseInterface; use Hyperf\HttpServer\Response; use Hyperf\Utils\ApplicationContext; use Hyperf\Utils\Context; @@ -22,6 +24,7 @@ use Mockery; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface as PsrResponseInterface; +use Swoole\Http\Response as SwooleResponse; /** * @internal @@ -173,4 +176,43 @@ class ResponseTest extends TestCase $this->assertInstanceOf(PsrResponseInterface::class, $response); } + + public function testCookiesAndHeaders() + { + $container = Mockery::mock(ContainerInterface::class); + ApplicationContext::setContainer($container); + + $swooleResponse = Mockery::mock(SwooleResponse::class); + $id = uniqid(); + $cookie1 = new Cookie('Name', 'Hyperf'); + $cookie2 = new Cookie('Request-Id', $id); + $swooleResponse->shouldReceive('status')->with(Mockery::any())->andReturn(200); + $swooleResponse->shouldReceive('header')->withAnyArgs()->andReturnUsing(function ($name, $value) { + if ($name == 'X-Token') { + $this->assertSame($value, 'xxx'); + } + return true; + }); + $swooleResponse->shouldReceive('rawcookie')->withAnyArgs()->twice()->andReturnUsing(function ($name, $value, ...$args) use ($id) { + $this->assertTrue($name == 'Name' || $name == 'Request-Id'); + $this->assertTrue($value == 'Hyperf' || $value == $id); + return true; + }); + $swooleResponse->shouldReceive('end')->once()->andReturn(true); + + Context::set(PsrResponseInterface::class, $psrResponse = new \Hyperf\HttpMessage\Server\Response($swooleResponse)); + + $response = new Response(); + $response = $response->cookie($cookie1)->cookie($cookie2)->header('X-Token', 'xxx'); + + $this->assertInstanceOf(Response::class, $response); + $this->assertInstanceOf(ResponseInterface::class, $response); + + $response = $response->raw('Hello Hyperf.'); + $this->assertNotInstanceOf(Response::class, $response); + $this->assertNotInstanceOf(ResponseInterface::class, $response); + $this->assertInstanceOf(PsrResponseInterface::class, $response); + + $response->send(); + } } From 3653f36b1d2871061d7a4920cdda078894e0ecfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 1 Sep 2019 18:44:09 +0800 Subject: [PATCH 180/225] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93717f457..3cea95031 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [#420](https://github.com/hyperf-cloud/hyperf/pull/420) Added listener for model. - [#441](https://github.com/hyperf-cloud/hyperf/pull/441) Automatically close the spare redis client when it is used in low frequency. - [#455](https://github.com/hyperf-cloud/hyperf/pull/455) Added `download()` method of `Hyperf\HttpServer\Contract\ResponseInterface`. +- [#500](https://github.com/hyperf-cloud/hyperf/pull/499) Added `cookie` and `header` method of `Hyperf\HttpServer\Contract\ResponseInterface`. ## Changed From da18cd9ce5cbd3c69502757728aaeea07d5dc23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Sun, 1 Sep 2019 18:49:50 +0800 Subject: [PATCH 181/225] Update ResponseTest.php --- src/http-server/tests/ResponseTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http-server/tests/ResponseTest.php b/src/http-server/tests/ResponseTest.php index ed26ace40..28991fcbe 100644 --- a/src/http-server/tests/ResponseTest.php +++ b/src/http-server/tests/ResponseTest.php @@ -187,7 +187,7 @@ class ResponseTest extends TestCase $cookie1 = new Cookie('Name', 'Hyperf'); $cookie2 = new Cookie('Request-Id', $id); $swooleResponse->shouldReceive('status')->with(Mockery::any())->andReturn(200); - $swooleResponse->shouldReceive('header')->withAnyArgs()->andReturnUsing(function ($name, $value) { + $swooleResponse->shouldReceive('header')->withAnyArgs()->twice()->andReturnUsing(function ($name, $value) { if ($name == 'X-Token') { $this->assertSame($value, 'xxx'); } From d01fa287c6227237eb29dc52902b1e7e358c26ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 2 Sep 2019 09:46:07 +0800 Subject: [PATCH 182/225] Deleted annotation.cache when execute di:init-proxy. --- src/di/src/Command/InitProxyCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/di/src/Command/InitProxyCommand.php b/src/di/src/Command/InitProxyCommand.php index 22adb3157..00c2cb838 100644 --- a/src/di/src/Command/InitProxyCommand.php +++ b/src/di/src/Command/InitProxyCommand.php @@ -91,7 +91,7 @@ class InitProxyCommand extends Command { $scanDirs = $this->getScanDir(); - $runtime = BASE_PATH . '/runtime/container/proxy/'; + $runtime = BASE_PATH . '/runtime/container/'; if (is_dir($runtime)) { $this->clearRuntime($runtime); } From 9398486157213b3c24dd824de62f0939bbdb2243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 2 Sep 2019 09:56:51 +0800 Subject: [PATCH 183/225] Update methods of withXxx return not only psr response. --- .../src/Contract/ResponseInterface.php | 9 +--- src/http-server/src/Response.php | 43 +++++++++++-------- src/http-server/tests/ResponseTest.php | 7 ++- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/http-server/src/Contract/ResponseInterface.php b/src/http-server/src/Contract/ResponseInterface.php index e1810ae15..3f79a22a6 100644 --- a/src/http-server/src/Contract/ResponseInterface.php +++ b/src/http-server/src/Contract/ResponseInterface.php @@ -57,12 +57,5 @@ interface ResponseInterface /** * Override a response with a cookie. */ - public function cookie(Cookie $cookie): ResponseInterface; - - /** - * Override a response with a header. - * - * @param string|string[] $value - */ - public function header(string $name, $value): ResponseInterface; + public function withCookie(Cookie $cookie): ResponseInterface; } diff --git a/src/http-server/src/Response.php b/src/http-server/src/Response.php index b9fc7db36..33f686e90 100644 --- a/src/http-server/src/Response.php +++ b/src/http-server/src/Response.php @@ -164,7 +164,7 @@ class Response implements PsrResponseInterface, ResponseInterface ->withBody(new SwooleFileStream($file)); } - public function cookie(Cookie $cookie): ResponseInterface + public function withCookie(Cookie $cookie): ResponseInterface { Context::override(PsrResponseInterface::class, function ($response) use ($cookie) { if (! $response instanceof ServerResponse) { @@ -176,18 +176,6 @@ class Response implements PsrResponseInterface, ResponseInterface return $this; } - public function header(string $name, $value): ResponseInterface - { - Context::override(PsrResponseInterface::class, function ($response) use ($name, $value) { - if (! $response instanceof PsrResponseInterface) { - throw new InvalidResponseException('The response is not instanceof ' . PsrResponseInterface::class); - } - return $response->withHeader($name, $value); - }); - - return $this; - } - /** * Retrieves the HTTP protocol version as a string. * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0"). @@ -212,7 +200,7 @@ class Response implements PsrResponseInterface, ResponseInterface */ public function withProtocolVersion($version) { - return $this->getResponse()->withProtocolVersion($version); + return $this->call(__FUNCTION__, func_get_args()); } /** @@ -307,7 +295,7 @@ class Response implements PsrResponseInterface, ResponseInterface */ public function withHeader($name, $value) { - return $this->getResponse()->withHeader($name, $value); + return $this->call(__FUNCTION__, func_get_args()); } /** @@ -326,7 +314,7 @@ class Response implements PsrResponseInterface, ResponseInterface */ public function withAddedHeader($name, $value) { - return $this->getResponse()->withAddedHeader($name, $value); + return $this->call(__FUNCTION__, func_get_args()); } /** @@ -341,7 +329,7 @@ class Response implements PsrResponseInterface, ResponseInterface */ public function withoutHeader($name) { - return $this->getResponse()->withoutHeader($name); + return $this->call(__FUNCTION__, func_get_args()); } /** @@ -367,7 +355,7 @@ class Response implements PsrResponseInterface, ResponseInterface */ public function withBody(StreamInterface $body) { - return $this->getResponse()->withBody($body); + return $this->call(__FUNCTION__, func_get_args()); } /** @@ -402,7 +390,7 @@ class Response implements PsrResponseInterface, ResponseInterface */ public function withStatus($code, $reasonPhrase = '') { - return $this->getResponse()->withStatus($code, $reasonPhrase); + return $this->call(__FUNCTION__, func_get_args()); } /** @@ -422,6 +410,23 @@ class Response implements PsrResponseInterface, ResponseInterface return $this->getResponse()->getReasonPhrase(); } + protected function call($name, $arguments) + { + Context::override(PsrResponseInterface::class, function ($response) use ($name, $arguments) { + if (! $response instanceof PsrResponseInterface) { + throw new InvalidResponseException('The response is not instanceof ' . PsrResponseInterface::class); + } + + if (! method_exists($response, $name)) { + throw new BadMethodCallException(sprintf('Call to undefined method %s::%s()', get_class($this), $name)); + } + + return $response->{$name}(...$arguments); + }); + + return $this; + } + /** * Get ETag header according to the checksum of the file. */ diff --git a/src/http-server/tests/ResponseTest.php b/src/http-server/tests/ResponseTest.php index 28991fcbe..6cc75c147 100644 --- a/src/http-server/tests/ResponseTest.php +++ b/src/http-server/tests/ResponseTest.php @@ -175,6 +175,7 @@ class ResponseTest extends TestCase $response = $response->withBody(new SwooleStream('xxx')); $this->assertInstanceOf(PsrResponseInterface::class, $response); + $this->assertInstanceOf(ResponseInterface::class, $response); } public function testCookiesAndHeaders() @@ -186,7 +187,9 @@ class ResponseTest extends TestCase $id = uniqid(); $cookie1 = new Cookie('Name', 'Hyperf'); $cookie2 = new Cookie('Request-Id', $id); - $swooleResponse->shouldReceive('status')->with(Mockery::any())->andReturn(200); + $swooleResponse->shouldReceive('status')->with(Mockery::any())->andReturnUsing(function ($code) { + $this->assertSame($code, 200); + }); $swooleResponse->shouldReceive('header')->withAnyArgs()->twice()->andReturnUsing(function ($name, $value) { if ($name == 'X-Token') { $this->assertSame($value, 'xxx'); @@ -203,7 +206,7 @@ class ResponseTest extends TestCase Context::set(PsrResponseInterface::class, $psrResponse = new \Hyperf\HttpMessage\Server\Response($swooleResponse)); $response = new Response(); - $response = $response->cookie($cookie1)->cookie($cookie2)->header('X-Token', 'xxx'); + $response = $response->withCookie($cookie1)->withCookie($cookie2)->withHeader('X-Token', 'xxx')->withStatus(200); $this->assertInstanceOf(Response::class, $response); $this->assertInstanceOf(ResponseInterface::class, $response); From 1d59fe56d6a61be539a904b2885177d9f8d7e9b3 Mon Sep 17 00:00:00 2001 From: linchunbo Date: Mon, 2 Sep 2019 16:03:39 +0800 Subject: [PATCH 184/225] =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E7=AB=A0=E8=8A=82=E4=B8=8B=E9=9D=A2=E3=80=90?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8B=E8=BD=BD=E3=80=91=E6=AE=B5=E8=90=BD?= =?UTF-8?q?=E9=94=99=E5=88=AB=E5=AD=97=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/zh/response.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/response.md b/doc/zh/response.md index 09fed43a1..b95eda912 100644 --- a/doc/zh/response.md +++ b/doc/zh/response.md @@ -128,7 +128,7 @@ class IndexController ## 文件下载 `Hyperf\HttpServer\Contract\ResponseInterface` 提供了 `download(string $file, string $name = '')` 返回一个已设置下载文件状态的 `Psr7ResponseInterface` 对象。 -如果请求中带有 `if-match` 或 `if-none-match` 的请求头,Hyperf 也会跟根据协议标准与 `ETag` 进行比较,如果一致则会返回一个 `304` 状态码的响应。 +如果请求中带有 `if-match` 或 `if-none-match` 的请求头,Hyperf 也会根据协议标准与 `ETag` 进行比较,如果一致则会返回一个 `304` 状态码的响应。 `download` 方法: From 94917fa1ff9d8ec2d77008e3da3240e78494707c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 2 Sep 2019 16:05:54 +0800 Subject: [PATCH 185/225] Do not use override. --- src/http-server/src/Response.php | 28 +++++++--------------- src/http-server/src/ResponseInstance.php | 30 ++++++++++++++++++++++++ src/http-server/tests/ResponseTest.php | 2 ++ 3 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 src/http-server/src/ResponseInstance.php diff --git a/src/http-server/src/Response.php b/src/http-server/src/Response.php index 33f686e90..fbd866557 100644 --- a/src/http-server/src/Response.php +++ b/src/http-server/src/Response.php @@ -14,7 +14,6 @@ namespace Hyperf\HttpServer; use BadMethodCallException; use Hyperf\HttpMessage\Cookie\Cookie; -use Hyperf\HttpMessage\Server\Response as ServerResponse; use Hyperf\HttpMessage\Stream\SwooleFileStream; use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\HttpServer\Contract\ResponseInterface; @@ -166,14 +165,7 @@ class Response implements PsrResponseInterface, ResponseInterface public function withCookie(Cookie $cookie): ResponseInterface { - Context::override(PsrResponseInterface::class, function ($response) use ($cookie) { - if (! $response instanceof ServerResponse) { - throw new InvalidResponseException('The response is not instanceof ' . ServerResponse::class); - } - return $response->withCookie($cookie); - }); - - return $this; + return $this->call(__FUNCTION__, func_get_args()); } /** @@ -412,19 +404,17 @@ class Response implements PsrResponseInterface, ResponseInterface protected function call($name, $arguments) { - Context::override(PsrResponseInterface::class, function ($response) use ($name, $arguments) { - if (! $response instanceof PsrResponseInterface) { - throw new InvalidResponseException('The response is not instanceof ' . PsrResponseInterface::class); - } + $response = $this->getResponse(); - if (! method_exists($response, $name)) { - throw new BadMethodCallException(sprintf('Call to undefined method %s::%s()', get_class($this), $name)); - } + if (! $response instanceof PsrResponseInterface) { + throw new InvalidResponseException('The response is not instanceof ' . PsrResponseInterface::class); + } - return $response->{$name}(...$arguments); - }); + if (! method_exists($response, $name)) { + throw new BadMethodCallException(sprintf('Call to undefined method %s::%s()', get_class($this), $name)); + } - return $this; + return new ResponseInstance($response->{$name}(...$arguments)); } /** diff --git a/src/http-server/src/ResponseInstance.php b/src/http-server/src/ResponseInstance.php new file mode 100644 index 000000000..f77a37826 --- /dev/null +++ b/src/http-server/src/ResponseInstance.php @@ -0,0 +1,30 @@ +response = $response; + } + + public function getResponse() + { + return $this->response; + } +} diff --git a/src/http-server/tests/ResponseTest.php b/src/http-server/tests/ResponseTest.php index 6cc75c147..4f830559b 100644 --- a/src/http-server/tests/ResponseTest.php +++ b/src/http-server/tests/ResponseTest.php @@ -217,5 +217,7 @@ class ResponseTest extends TestCase $this->assertInstanceOf(PsrResponseInterface::class, $response); $response->send(); + + $this->assertSame($psrResponse, Context::get(PsrResponseInterface::class)); } } From ac07640db9d3488d190b41d83cc8367fdb53f583 Mon Sep 17 00:00:00 2001 From: linchunbo Date: Mon, 2 Sep 2019 16:06:02 +0800 Subject: [PATCH 186/225] =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86=E7=AB=A0=E8=8A=82=E4=B8=8B?= =?UTF-8?q?=E9=9D=A2=E3=80=90=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86=E5=99=A8?= =?UTF-8?q?=E3=80=91=E6=AE=B5=E8=90=BD=E9=94=99=E5=88=AB=E5=AD=97=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/zh/exception-handler.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/exception-handler.md b/doc/zh/exception-handler.md index 68fb2ab38..d7efc3ccd 100644 --- a/doc/zh/exception-handler.md +++ b/doc/zh/exception-handler.md @@ -1,6 +1,6 @@ # 异常处理器 -在 `Hyperf` 里,业务代码都运行在 `Worker进程` 上,也就意味着一旦任意一个请求的业务存在没有捕获处理的异常的话,都会导致对应的 `Worker进程` 被中断退出,虽然被中断的 `Worker进程` 仍会被重新拉起,但对服务而已也是不能接受的,且捕获异常并输出合理的报错内容给客户端也是更加友好的。 +在 `Hyperf` 里,业务代码都运行在 `Worker进程` 上,也就意味着一旦任意一个请求的业务存在没有捕获处理的异常的话,都会导致对应的 `Worker进程` 被中断退出,虽然被中断的 `Worker进程` 仍会被重新拉起,但对服务而言也是不能接受的,且捕获异常并输出合理的报错内容给客户端也是更加友好的。 我们可以通过对各个 `server` 定义不同的 `异常处理器(ExceptionHandler)`,一旦业务流程存在没有捕获的异常,都会被传递到已注册的 `异常处理器(ExceptionHandler)` 去处理。 ## 自定义一个异常处理 From 0a9d892d4fe28a2a4217b7f48f3dfe510e04fd5f Mon Sep 17 00:00:00 2001 From: linchunbo Date: Mon, 2 Sep 2019 16:10:18 +0800 Subject: [PATCH 187/225] =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E7=AB=A0=E8=8A=82=E4=B8=8B=E9=9D=A2=E3=80=90?= =?UTF-8?q?=E6=B8=85=E7=90=86=E6=B3=A8=E8=A7=A3=E7=BC=93=E5=AD=98=E3=80=91?= =?UTF-8?q?=E6=AE=B5=E8=90=BD=E9=94=99=E5=88=AB=E5=AD=97=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/zh/cache.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/cache.md b/doc/zh/cache.md index 9ed42cd07..1e98de982 100644 --- a/doc/zh/cache.md +++ b/doc/zh/cache.md @@ -74,7 +74,7 @@ class UserService ### 清理注解缓存 -当然,如果我们数据库中的数据改变了,如果删除缓存呢?这里就需要用到后面的监听器。下面新建一个 Service 提供一方法,来帮我们处理缓存。 +当然,如果我们数据库中的数据改变了,如何删除缓存呢?这里就需要用到后面的监听器。下面新建一个 Service 提供一方法,来帮我们处理缓存。 ```php Date: Mon, 2 Sep 2019 17:43:46 +0800 Subject: [PATCH 188/225] Update communication.md --- doc/zh/communication.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/zh/communication.md b/doc/zh/communication.md index f974796ad..507352840 100644 --- a/doc/zh/communication.md +++ b/doc/zh/communication.md @@ -10,4 +10,8 @@ 由于微信群无法直接加入,故可先加下方二维码好友,并声明目的,再拉您入群。 -![wechat](./imgs/wechat.jpg ':size=375') \ No newline at end of file +## Contributor 群 + +为了更好的发展 Hyperf 的社区,我们专门为 Hyperf Contributor 提供了一个微信群,以便我们对 Pull Request 或迭代计划进行更详细的探讨,由于微信群无法直接加入,故可先加下方二维码好友,并声明目的且带上您已经被 Merged 的 Pull Request,再拉您入群。 + +![wechat](./imgs/wechat.jpg ':size=375') From 5883565382188d5a686ef40c2a9602caffb69a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Mon, 2 Sep 2019 17:44:30 +0800 Subject: [PATCH 189/225] Update di.md --- doc/zh/di.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/di.md b/doc/zh/di.md index fbc4081da..ab291f81a 100644 --- a/doc/zh/di.md +++ b/doc/zh/di.md @@ -95,7 +95,7 @@ class IndexController } ``` -> 注意调用方也就是 `IndexController` 必须是由 DI 创建的对象才能完成自动注入,Controller 默认是由 DI 创建的 +> 注意调用方也就是 `IndexController` 必须是由 DI 创建的对象才能完成自动注入,Controller 默认是由 DI 创建的,直接 `new` 该对象不会生效; > 使用 `@Inject` 注解时需 `use Hyperf\Di\Annotation\Inject;` 命名空间; From 5f3ac8ed7f03e0f2559f66acd6904d1c19d88b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 2 Sep 2019 18:34:58 +0800 Subject: [PATCH 190/225] Optimized code. --- src/http-server/src/Response.php | 16 ++++++++++++- src/http-server/src/ResponseInstance.php | 30 ------------------------ 2 files changed, 15 insertions(+), 31 deletions(-) delete mode 100644 src/http-server/src/ResponseInstance.php diff --git a/src/http-server/src/Response.php b/src/http-server/src/Response.php index fbd866557..f8bc1033d 100644 --- a/src/http-server/src/Response.php +++ b/src/http-server/src/Response.php @@ -39,6 +39,16 @@ class Response implements PsrResponseInterface, ResponseInterface { use Macroable; + /** + * @var null|PsrResponseInterface + */ + protected $response; + + public function __construct(?PsrResponseInterface $response = null) + { + $this->response = $response; + } + public function __call($name, $arguments) { $response = $this->getResponse(); @@ -414,7 +424,7 @@ class Response implements PsrResponseInterface, ResponseInterface throw new BadMethodCallException(sprintf('Call to undefined method %s::%s()', get_class($this), $name)); } - return new ResponseInstance($response->{$name}(...$arguments)); + return new static($response->{$name}(...$arguments)); } /** @@ -500,6 +510,10 @@ class Response implements PsrResponseInterface, ResponseInterface */ protected function getResponse() { + if ($this->response instanceof PsrResponseInterface) { + return $this->response; + } + return Context::get(PsrResponseInterface::class); } } diff --git a/src/http-server/src/ResponseInstance.php b/src/http-server/src/ResponseInstance.php deleted file mode 100644 index f77a37826..000000000 --- a/src/http-server/src/ResponseInstance.php +++ /dev/null @@ -1,30 +0,0 @@ -response = $response; - } - - public function getResponse() - { - return $this->response; - } -} From b39257383521757cabf1ca68f03d447b4d871077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Tue, 3 Sep 2019 01:41:27 +0800 Subject: [PATCH 191/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef14587ae..d89dd3962 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ - [#420](https://github.com/hyperf-cloud/hyperf/pull/420) Added listener for model. - [#441](https://github.com/hyperf-cloud/hyperf/pull/441) Automatically close the spare redis client when it is used in low frequency. - [#455](https://github.com/hyperf-cloud/hyperf/pull/455) Added `download()` method of `Hyperf\HttpServer\Contract\ResponseInterface`. -- [#500](https://github.com/hyperf-cloud/hyperf/pull/499) Added `cookie` and `header` method of `Hyperf\HttpServer\Contract\ResponseInterface`. +- [#500](https://github.com/hyperf-cloud/hyperf/pull/499) Added fluent method calls of `Hyperf\HttpServer\Contract\ResponseInterface`. ## Changed From d464c27b25f56b7fc4ffcb10a2113e15f438432f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Tue, 3 Sep 2019 10:05:35 +0800 Subject: [PATCH 192/225] Update swoole-tracker.md --- doc/zh/swoole-tracker.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/zh/swoole-tracker.md b/doc/zh/swoole-tracker.md index dce14eb80..92f16c738 100644 --- a/doc/zh/swoole-tracker.md +++ b/doc/zh/swoole-tracker.md @@ -1,6 +1,6 @@ # Swoole Tracker -[Swoole Tracker](https://www.swoole-cloud.com/tracker.html) 作为 `Swoole` 官方出品的一整套企业级`PHP`和`Swoole`分析调试工具,更专一、更专业。 +[Swoole Tracker](https://www.swoole-cloud.com/tracker.html) 作为 `Swoole` 官方出品的一整套企业级 `PHP` 和 `Swoole`分析调试工具,更专一、更专业。(曾命名:Swoole Enterprise) - 时刻掌握应用架构模型 > 自动发现应用依赖拓扑结构和展示,时刻掌握应用的架构模型 @@ -117,17 +117,17 @@ ENTRYPOINT ["sh", ".build/entrypoint.sh"] ### 不依赖组件 -`Swoole Tracker`的`v2.5.0`版本支持自动生成应用名称并创建应用,无需修改任何代码,生成的应用名称格式为: +`Swoole Tracker` 的 `v2.5.0` 以上版本支持自动生成应用名称并创建应用,无需修改任何代码,生成的应用名称格式为: -`Swoole`的`HttpServer`:`ip:prot` +`Swoole` 的 `HttpServer:ip:port` -其他的`Server`:`ip(hostname):prot` +其他的 `Server:ip(hostname):port` -即安装好`swoole_tracker`扩展之后就可以正常使用`Swoole Tracker`的功能 +即安装好 `swoole_tracker` 扩展之后就可以正常使用 `Swoole Tracker` 的功能 ### 依赖组件 -当你需要自定义应用名称时则需要安装组件,使用`Composer`安装: +当你需要自定义应用名称时则需要安装组件,使用 `Composer` 安装: ```bash composer require hyperf/swoole-tracker From d216951fe7ec8c831d2ba72717ed0da6ebdfc0ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Tue, 3 Sep 2019 10:06:40 +0800 Subject: [PATCH 193/225] Remove useless scan --- src/swoole-tracker/src/ConfigProvider.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/swoole-tracker/src/ConfigProvider.php b/src/swoole-tracker/src/ConfigProvider.php index 31ebb7e16..448dce5c2 100644 --- a/src/swoole-tracker/src/ConfigProvider.php +++ b/src/swoole-tracker/src/ConfigProvider.php @@ -23,7 +23,6 @@ class ConfigProvider ], 'scan' => [ 'paths' => [ - __DIR__, ], ], ]; From f66bc7f84dfea610d16098b9bc631c5489af4d1e Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Tue, 3 Sep 2019 10:31:36 +0800 Subject: [PATCH 194/225] Update swoole-tracker.md --- doc/zh/swoole-tracker.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/zh/swoole-tracker.md b/doc/zh/swoole-tracker.md index 92f16c738..190b4a916 100644 --- a/doc/zh/swoole-tracker.md +++ b/doc/zh/swoole-tracker.md @@ -41,7 +41,7 @@ php /opt/www/bin/hyperf.php start 2. `swoole-tracker.ini` ```bash -[swoole_plus] +[swoole_tracker] extension=/opt/swoole_tracker.so apm.enable=1 #打开总开关 apm.sampling_rate=100 #采样率 例如:100% @@ -117,11 +117,11 @@ ENTRYPOINT ["sh", ".build/entrypoint.sh"] ### 不依赖组件 -`Swoole Tracker` 的 `v2.5.0` 以上版本支持自动生成应用名称并创建应用,无需修改任何代码,生成的应用名称格式为: +`Swoole Tracker` 的 `v2.5.0` 以上版本支持自动生成应用名称并创建应用,无需修改任何代码。 -`Swoole` 的 `HttpServer:ip:port` +如果使用 `Swoole` 的 `HttpServer` 那么生成的应用名称为`ip:port` -其他的 `Server:ip(hostname):port` +如果使用 `Swoole` 其他的 `Server` 那么生成的应用名称为`ip(hostname):port` 即安装好 `swoole_tracker` 扩展之后就可以正常使用 `Swoole Tracker` 的功能 From 305772d84da3c3927be6caaf4243645e51eb7161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8B=82=E5=A5=94=E7=9A=84=E8=9A=82=E8=9A=81?= Date: Tue, 3 Sep 2019 10:36:57 +0800 Subject: [PATCH 195/225] =?UTF-8?q?=E6=96=87=E6=A1=A3=E9=94=99=E5=88=AB?= =?UTF-8?q?=E5=AD=97=E2=9D=8C=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 文档错别字❌修改 --- doc/zh/component-guide/configprovider.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/zh/component-guide/configprovider.md b/doc/zh/component-guide/configprovider.md index ca22e8749..b1c7f5895 100644 --- a/doc/zh/component-guide/configprovider.md +++ b/doc/zh/component-guide/configprovider.md @@ -68,11 +68,11 @@ class ConfigProvider # 组件设计规范 -由于 `composer.json` 内的 `extra` 属性在数据不被利用时无其它作用和影响,顾这些组件内的定义在其它框架使用时,不会造成任何的干扰和影响,顾 `ConfigProvider` 是一种仅作用于 Hyperf 框架的机制,对其它没有利用此机制的框架不会造成任何的影响,这也就为组件的复用打下了基础,但这也要求在进行组件设计时,必须遵循以下规范: +由于 `composer.json` 内的 `extra` 属性在数据不被利用时无其它作用和影响,故这些组件内的定义在其它框架使用时,不会造成任何的干扰和影响,顾 `ConfigProvider` 是一种仅作用于 Hyperf 框架的机制,对其它没有利用此机制的框架不会造成任何的影响,这也就为组件的复用打下了基础,但这也要求在进行组件设计时,必须遵循以下规范: - 所有类的设计都必须允许通过标准 `OOP` 的使用方式来使用,所有 Hyperf 专有的功能必须作为增强功能并以单独的类来提供,也就意味着在非 Hyperf 框架下仍能通过标准的手段来实现组件的使用; - 组件的依赖设计如果可满足 [PSR 标准](https://www.php-fig.org/psr) 则优先满足且依赖对应的接口而不是实现类;如 [PSR 标准](https://www.php-fig.org/psr) 没有包含的功能,则可满足由 Hyperf 定义的契约库 [Hyperf/contract](https://github.com/hyperf-cloud/contract) 内的接口时优先满足且依赖对应的接口而不是实现类; - 对于实现 Hyperf 专有功能所增加的增强功能类,通常来说也会对 Hyperf 的一些组件有依赖,那么这些组件的依赖不应该写在 `composer.json` 的 `require` 项,而是写在 `suggust` 项作为建议项存在; - 组件设计时不应该通过注解进行任何的依赖注入,注入方式应只使用 `构造函数注入` 的方式,这样同时也能满足在 `OOP` 下的使用; - 组件设计时不应该通过注解进行任何的功能定义,功能定义应只通过 `ConfigProvider` 来定义; -- 类的设计时应尽可能的不储存状态数据,因为这会导致这个类不能作为长生命周期的对象来提供,也无法很方便的使用依赖注入功能,这样会在一定程度下降低性能,状态数据应都通过 `Hyperf\Utils\Context` 协程上下文来储存; \ No newline at end of file +- 类的设计时应尽可能的不储存状态数据,因为这会导致这个类不能作为长生命周期的对象来提供,也无法很方便的使用依赖注入功能,这样会在一定程度下降低性能,状态数据应都通过 `Hyperf\Utils\Context` 协程上下文来储存; From 7b6452824d97917f8dc3627df6c02cb57ebdb242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 11:24:50 +0800 Subject: [PATCH 196/225] Added aliyun logger. --- doc/zh/summary.md | 1 + doc/zh/tutorial/aliyun-logger.md | 141 +++++++++++++++++++++++++++++++ doc/zh/view.md | 10 +-- 3 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 doc/zh/tutorial/aliyun-logger.md diff --git a/doc/zh/summary.md b/doc/zh/summary.md index d0f0e32f4..94b62331e 100644 --- a/doc/zh/summary.md +++ b/doc/zh/summary.md @@ -86,6 +86,7 @@ * [DaoCloud Devops 搭建](zh/tutorial/daocloud.md) * [Supervisor 部署](zh/tutorial/supervisor.md) * [Nginx 反向代理](zh/tutorial/nginx.md) + * [阿里云日志服务](zh/tutorial/aliyun-logger.md) * Awesome Hyperf diff --git a/doc/zh/tutorial/aliyun-logger.md b/doc/zh/tutorial/aliyun-logger.md new file mode 100644 index 000000000..2e30b6f7e --- /dev/null +++ b/doc/zh/tutorial/aliyun-logger.md @@ -0,0 +1,141 @@ +# 阿里云日志服务 + +在 `Docker集群` 部署项目时,收集日志会是一个比较麻烦的问题,但阿里云提供了十分好用的 `日志收集系统`,本篇文档就是简略介绍一下阿里云日志收集的使用方法。 + +* [Docker Swarm 集群搭建](zh/tutorial/docker-swarm.md) + +## 开通日志服务 + +首先第一步便是在阿里云上开通 `日志服务`。 + +[文档](https://help.aliyun.com/product/28958.html?spm=a2c4g.11186623.6.540.12bac9b5C46s8N) + +以下的教程是一个顺序的操作方式,一步一步讲述如何使用日志服务。 + +## 安装 Logtail + +`Logtail客户端` 是日志服务提供的日志采集客户端 + +[文档](https://help.aliyun.com/document_detail/28982.html?spm=a2c4g.11186623.6.600.bd666a16cEkLw2) + +``` +wget http://logtail-release-${your_region_name}.oss-${your_region_name}-internal.aliyuncs.com/linux64/logtail.sh -O logtail.sh; chmod 755 logtail.sh; ./logtail.sh install ${your_region_name} +``` + +以下为杭州ECS的安装实例 + +``` +wget http://logtail-release-cn-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/linux64/logtail.sh -O logtail.sh; chmod 755 logtail.sh; ./logtail.sh install cn-hangzhou +``` + +## 创建机器组 + +日志服务通过机器组的方式管理所有需要通过 `Logtail` 客户端收集日志的服务器。 + +机器组是包含多台服务器的虚拟分组。如果您有一台以上的服务器,并希望这些服务器使用同样的 `Logtail` 配置采集日志,可以将这些服务器加入同一个机器组,并将 `Logtail` 配置应用到该机器组。 + +### 自定义标识机器组 + +假设我们的机器组 名为 `Hyperf`。则修改 `/etc/ilogtail/user_defined_id` 文件,输入 `Hyperf`。 + +``` +$ cat /etc/ilogtail/user_defined_id +Hyperf +``` + +## 安装 Logtail容器 + +[文档](https://help.aliyun.com/document_detail/66659.html?spm=a2c4g.11186623.2.15.52d541865uv5Xr) + +| 参数 | 说明 | +|:-------------------------------------:|:---------------------------------------------------:| +| ${your_region_name} | 与 Logtail安装参数一致,比如华东1区域是 cn-hangzhou | +| ${your_aliyun_user_id} | 用户标识,请替换为您的阿里云主账号用户ID。 | +| ${your_machine_group_user_defined_id} | 集群的机器组自定义标识,即为上述的 Hyperf | + +``` +docker run -d -v /:/logtail_host:ro -v /var/run/docker.sock:/var/run/docker.sock \ +--env ALIYUN_LOGTAIL_CONFIG=/etc/ilogtail/conf/${your_region_name}/ilogtail_config.json \ +--env ALIYUN_LOGTAIL_USER_ID=${your_aliyun_user_id} \ +--env ALIYUN_LOGTAIL_USER_DEFINED_ID=${your_machine_group_user_defined_id} \ +registry.cn-hangzhou.aliyuncs.com/log-service/logtail +``` + +## 配置日志收集 + +### 创建 Project + +登录阿里云日志服务,点击 `创建Project`。填写以下信息 + +| 参数 | 填写示例 | +|:------------:|:----------------:| +| Project名称 | hyperf | +| 注释 | 用于日志系统演示 | +| 所属区域 | 华东1(杭州) | +| 开通服务 | 详细日志 | +| 日志存储位置 | 当前Project | + +### 创建 Logstore + +除以下参数,按需填写,其他都使用默认即可 + +| 参数 | 填写示例 | +|:------------:|:---------------:| +| Logstore名称 | hyperf-demo-api | +| 永久保存 | false | +| 数据保存时间 | 60 | + +### 接入数据 + +1. 选择 Docker文件 + +2. 创建机器组 + +如果已经创建国机器组,可以跳过这一步 + +| 参数 | 填写示例 | +|:--------------:|:--------------:| +| 机器组名称 | Hyperf | +| 机器组标识 | 用户自定义标识 | +| 用户自定义标识 | Hyperf | + +3. 配置机器组 + +应用刚刚创建的机器组 + +4. 配置 Logtail + +Label白名单 这里可以按需填写,以下按照项目名字来配置,而项目名会在Docker容器运行时设置。 + +| 参数 | 填写示例 | +|:--------------:|:-------------------------------------------------:| +| 配置名称 | hyperf-demo-api | +| 日志路径 | /opt/www/runtime/logs *.log | +| Label白名单 | app.name hyperf-demo-api | +| 模式 | 完整正则模式 | +| 单行模式 | false | +| 日志样例 | [2019-03-07 11:58:57] hyperf.WARNING: xxx | +| 首行正则表达式 | \[\d+-\d+-\d+\s\d+:\d+:\d+\]\s.* | +| 提取字段 | true | +| 正则表达式 | \[(\d+-\d+-\d+\s\d+:\d+:\d+)\]\s(\w+)\.(\w+):(.*) | +| 日志抽取内容 | time name level content | + +5. 查询分析配置 + +字段索引属性 + +| 字段名称 | 类型 | 别名 | 中文分词 | 开启统计 | +|:--------:|:----:|:-------:|:--------:|:--------:| +| name | text | name | false | true | +| level | text | level | false | true | +| time | text | time | false | false | +| content | text | content | true | false | + +### 运行镜像 + +运行镜像时,只需要设置 Container labels 即可。 + +| name | value | +|:--------:|:---------------:| +| app.name | hyperf-demo-api | + diff --git a/doc/zh/view.md b/doc/zh/view.md index 19f1439b6..c5129a0d4 100644 --- a/doc/zh/view.md +++ b/doc/zh/view.md @@ -12,12 +12,12 @@ composer require hyperf/view View 组件的配置文件位于 `config/autoload/view.php`,若配置文件不存在可自行创建,以下为相关配置的说明: -| 配置 | 类型 | 默认值 | 备注 | -|:-----------------:|:------:|:--------------------------------------:|:----------------:| +| 配置 | 类型 | 默认值 | 备注 | +|:-----------------:|:------:|:-------------------------------------:|:----------------:| | engine | string | Hyperf\View\Engine\BladeEngine::class | 视图渲染引擎 | -| mode | string | Mode::TASK | 视图渲染模式 | -| config.view_path | string | 无 | 视图文件默认地址 | -| config.cache_path | string | 无 | 视图文件缓存地址 | +| mode | string | Mode::TASK | 视图渲染模式 | +| config.view_path | string | 无 | 视图文件默认地址 | +| config.cache_path | string | 无 | 视图文件缓存地址 | 配置文件格式示例: From e7ba513853519e02f781a4c424461b4e738c62eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 12:18:02 +0800 Subject: [PATCH 197/225] Update aliyun-logger.md --- doc/zh/tutorial/aliyun-logger.md | 33 +------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/doc/zh/tutorial/aliyun-logger.md b/doc/zh/tutorial/aliyun-logger.md index 2e30b6f7e..4ead07c74 100644 --- a/doc/zh/tutorial/aliyun-logger.md +++ b/doc/zh/tutorial/aliyun-logger.md @@ -12,44 +12,13 @@ 以下的教程是一个顺序的操作方式,一步一步讲述如何使用日志服务。 -## 安装 Logtail - -`Logtail客户端` 是日志服务提供的日志采集客户端 - -[文档](https://help.aliyun.com/document_detail/28982.html?spm=a2c4g.11186623.6.600.bd666a16cEkLw2) - -``` -wget http://logtail-release-${your_region_name}.oss-${your_region_name}-internal.aliyuncs.com/linux64/logtail.sh -O logtail.sh; chmod 755 logtail.sh; ./logtail.sh install ${your_region_name} -``` - -以下为杭州ECS的安装实例 - -``` -wget http://logtail-release-cn-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/linux64/logtail.sh -O logtail.sh; chmod 755 logtail.sh; ./logtail.sh install cn-hangzhou -``` - -## 创建机器组 - -日志服务通过机器组的方式管理所有需要通过 `Logtail` 客户端收集日志的服务器。 - -机器组是包含多台服务器的虚拟分组。如果您有一台以上的服务器,并希望这些服务器使用同样的 `Logtail` 配置采集日志,可以将这些服务器加入同一个机器组,并将 `Logtail` 配置应用到该机器组。 - -### 自定义标识机器组 - -假设我们的机器组 名为 `Hyperf`。则修改 `/etc/ilogtail/user_defined_id` 文件,输入 `Hyperf`。 - -``` -$ cat /etc/ilogtail/user_defined_id -Hyperf -``` - ## 安装 Logtail容器 [文档](https://help.aliyun.com/document_detail/66659.html?spm=a2c4g.11186623.2.15.52d541865uv5Xr) | 参数 | 说明 | |:-------------------------------------:|:---------------------------------------------------:| -| ${your_region_name} | 与 Logtail安装参数一致,比如华东1区域是 cn-hangzhou | +| ${your_region_name} | 区域ID 比如华东1区域是 cn-hangzhou | | ${your_aliyun_user_id} | 用户标识,请替换为您的阿里云主账号用户ID。 | | ${your_machine_group_user_defined_id} | 集群的机器组自定义标识,即为上述的 Hyperf | From 090e69eb575371d1ca5a772482530ba7e422e54e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 13:51:38 +0800 Subject: [PATCH 198/225] Update aliyun-logger.md --- doc/zh/tutorial/aliyun-logger.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/zh/tutorial/aliyun-logger.md b/doc/zh/tutorial/aliyun-logger.md index 4ead07c74..75d0cc9d2 100644 --- a/doc/zh/tutorial/aliyun-logger.md +++ b/doc/zh/tutorial/aliyun-logger.md @@ -108,3 +108,9 @@ Label白名单 这里可以按需填写,以下按照项目名字来配置, |:--------:|:---------------:| | app.name | hyperf-demo-api | +## 注意事项 + +- Docker存储驱动限制:目前只支持overlay、overlay2,其他存储驱动需将日志所在目录mount到本地。然后改为收集宿主机 /logtail_host/your_path 下的日志即可。 + + + From 0c72319c2db1045aa880dbf36b5b8aa4e737a009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 14:09:05 +0800 Subject: [PATCH 199/225] Update docker-swarm.md --- doc/zh/tutorial/docker-swarm.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/zh/tutorial/docker-swarm.md b/doc/zh/tutorial/docker-swarm.md index cf27a78c9..0e52cbf3a 100644 --- a/doc/zh/tutorial/docker-swarm.md +++ b/doc/zh/tutorial/docker-swarm.md @@ -301,6 +301,19 @@ docker run --rm --network=default-network -p 8080:8080 -d --name kong-dashboard 如果机器直接对外,最好只开放 `80` `443` 端口,然后把 `Kong` 容器的 `8000` 和 `8443` 映射到 `80` 和 `443` 上。 当然,如果使用了 `SLB` 等负载均衡,就直接通过负载均衡,把 `80` 和 `443` 映射到 `KONG` 所在几台机器的 `8000` `8443` 上。 +## 如何使用 Linux Crontab + +`Hyperf` 虽然提供了 `crontab` 组件,但是不一定可以满足所有人的需求,这里提供一个 `Linux` 使用的脚本,执行 `Docker` 内的 `Command`。 + +```bash +#!/usr/bin/env bash +basepath=$(cd `dirname $0`; pwd) +docker pull registry-vpc.cn-shanghai.aliyuncs.com/namespace/project:latest +docker run --rm -i -v $basepath/.env:/opt/www/.env \ +--entrypoint php registry-vpc.cn-shanghai.aliyuncs.com/namespace/project:latest \ +/opt/www/bin/hyperf.php your_command +``` + ## 意外情况 ### fatal: git fetch-pack: expected shallow list From 36f7b6c569fbf0f6be76eb4dec64fba1a94a117e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 14:26:39 +0800 Subject: [PATCH 200/225] Update aliyun-logger.md --- doc/zh/tutorial/aliyun-logger.md | 48 ++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/doc/zh/tutorial/aliyun-logger.md b/doc/zh/tutorial/aliyun-logger.md index 75d0cc9d2..83e71b9de 100644 --- a/doc/zh/tutorial/aliyun-logger.md +++ b/doc/zh/tutorial/aliyun-logger.md @@ -16,11 +16,11 @@ [文档](https://help.aliyun.com/document_detail/66659.html?spm=a2c4g.11186623.2.15.52d541865uv5Xr) -| 参数 | 说明 | -|:-------------------------------------:|:---------------------------------------------------:| -| ${your_region_name} | 区域ID 比如华东1区域是 cn-hangzhou | -| ${your_aliyun_user_id} | 用户标识,请替换为您的阿里云主账号用户ID。 | -| ${your_machine_group_user_defined_id} | 集群的机器组自定义标识,即为上述的 Hyperf | +| 参数 | 说明 | +|:-------------------------------------:|:------------------------------------------:| +| ${your_region_name} | 区域ID 比如华东1区域是 cn-hangzhou | +| ${your_aliyun_user_id} | 用户标识,请替换为您的阿里云主账号用户ID。 | +| ${your_machine_group_user_defined_id} | 集群的机器组自定义标识 以下使用 Hyperf | ``` docker run -d -v /:/logtail_host:ro -v /var/run/docker.sock:/var/run/docker.sock \ @@ -60,7 +60,7 @@ registry.cn-hangzhou.aliyuncs.com/log-service/logtail 2. 创建机器组 -如果已经创建国机器组,可以跳过这一步 +如果已经创建过机器组,可以跳过这一步 | 参数 | 填写示例 | |:--------------:|:--------------:| @@ -76,18 +76,18 @@ registry.cn-hangzhou.aliyuncs.com/log-service/logtail Label白名单 这里可以按需填写,以下按照项目名字来配置,而项目名会在Docker容器运行时设置。 -| 参数 | 填写示例 | -|:--------------:|:-------------------------------------------------:| -| 配置名称 | hyperf-demo-api | -| 日志路径 | /opt/www/runtime/logs *.log | -| Label白名单 | app.name hyperf-demo-api | -| 模式 | 完整正则模式 | -| 单行模式 | false | -| 日志样例 | [2019-03-07 11:58:57] hyperf.WARNING: xxx | -| 首行正则表达式 | \[\d+-\d+-\d+\s\d+:\d+:\d+\]\s.* | -| 提取字段 | true | -| 正则表达式 | \[(\d+-\d+-\d+\s\d+:\d+:\d+)\]\s(\w+)\.(\w+):(.*) | -| 日志抽取内容 | time name level content | +| 参数 | 填写示例 | 填写示例 | +|:--------------:|:-------------------------------------------------:|:---------------:| +| 配置名称 | hyperf-demo-api | | +| 日志路径 | /opt/www/runtime/logs | *.log | +| Label白名单 | app.name | hyperf-demo-api | +| 模式 | 完整正则模式 | | +| 单行模式 | false | | +| 日志样例 | [2019-03-07 11:58:57] hyperf.WARNING: xxx | | +| 首行正则表达式 | \[\d+-\d+-\d+\s\d+:\d+:\d+\]\s.* | | +| 提取字段 | true | | +| 正则表达式 | \[(\d+-\d+-\d+\s\d+:\d+:\d+)\]\s(\w+)\.(\w+):(.*) | | +| 日志抽取内容 | time name level content | | 5. 查询分析配置 @@ -108,6 +108,18 @@ Label白名单 这里可以按需填写,以下按照项目名字来配置, |:--------:|:---------------:| | app.name | hyperf-demo-api | +比如以下 Dockerfile + +``` +# Default Dockerfile + +FROM hyperf/hyperf:7.2-alpine-cli +LABEL maintainer="Hyperf Developers " version="1.0" license="MIT" app.name="hyperf-demo-api" + +... + +``` + ## 注意事项 - Docker存储驱动限制:目前只支持overlay、overlay2,其他存储驱动需将日志所在目录mount到本地。然后改为收集宿主机 /logtail_host/your_path 下的日志即可。 From 8722441f1d1c15f93b0d8c05c69098129abad0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Wed, 4 Sep 2019 14:32:56 +0800 Subject: [PATCH 201/225] Update aliyun-logger.md --- doc/zh/tutorial/aliyun-logger.md | 35 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/doc/zh/tutorial/aliyun-logger.md b/doc/zh/tutorial/aliyun-logger.md index 83e71b9de..da362969e 100644 --- a/doc/zh/tutorial/aliyun-logger.md +++ b/doc/zh/tutorial/aliyun-logger.md @@ -8,13 +8,13 @@ 首先第一步便是在阿里云上开通 `日志服务`。 -[文档](https://help.aliyun.com/product/28958.html?spm=a2c4g.11186623.6.540.12bac9b5C46s8N) +[日志服务文档](https://help.aliyun.com/product/28958.html) 以下的教程是一个顺序的操作方式,一步一步讲述如何使用日志服务。 -## 安装 Logtail容器 +## 安装 Logtail 容器 -[文档](https://help.aliyun.com/document_detail/66659.html?spm=a2c4g.11186623.2.15.52d541865uv5Xr) +[标准 Docker 日志采集流程文档](https://help.aliyun.com/document_detail/66659.html) | 参数 | 说明 | |:-------------------------------------:|:------------------------------------------:| @@ -34,7 +34,7 @@ registry.cn-hangzhou.aliyuncs.com/log-service/logtail ### 创建 Project -登录阿里云日志服务,点击 `创建Project`。填写以下信息 +登录阿里云日志服务,点击 `创建 Project`,填写以下信息 | 参数 | 填写示例 | |:------------:|:----------------:| @@ -48,25 +48,25 @@ registry.cn-hangzhou.aliyuncs.com/log-service/logtail 除以下参数,按需填写,其他都使用默认即可 -| 参数 | 填写示例 | +| 参数 | 填写示例 | |:------------:|:---------------:| | Logstore名称 | hyperf-demo-api | -| 永久保存 | false | -| 数据保存时间 | 60 | +| 永久保存 | false | +| 数据保存时间 | 60 | ### 接入数据 -1. 选择 Docker文件 +1. 选择 Docker 文件 2. 创建机器组 如果已经创建过机器组,可以跳过这一步 | 参数 | 填写示例 | -|:--------------:|:--------------:| -| 机器组名称 | Hyperf | -| 机器组标识 | 用户自定义标识 | -| 用户自定义标识 | Hyperf | +|:-------------:|:-------------:| +| 机器组名称 | Hyperf | +| 机器组标识 | 用户自定义标识 | +| 用户自定义标识 | Hyperf | 3. 配置机器组 @@ -74,7 +74,7 @@ registry.cn-hangzhou.aliyuncs.com/log-service/logtail 4. 配置 Logtail -Label白名单 这里可以按需填写,以下按照项目名字来配置,而项目名会在Docker容器运行时设置。 +`Label` 白名单,这里可以按需填写,以下按照项目名字来配置,而项目名会在 Docker 容器运行时设置。 | 参数 | 填写示例 | 填写示例 | |:--------------:|:-------------------------------------------------:|:---------------:| @@ -102,7 +102,7 @@ Label白名单 这里可以按需填写,以下按照项目名字来配置, ### 运行镜像 -运行镜像时,只需要设置 Container labels 即可。 +运行镜像时,只需要设置 Container `labels` 即可。 | name | value | |:--------:|:---------------:| @@ -110,19 +110,18 @@ Label白名单 这里可以按需填写,以下按照项目名字来配置, 比如以下 Dockerfile -``` +```Dockerfile # Default Dockerfile FROM hyperf/hyperf:7.2-alpine-cli LABEL maintainer="Hyperf Developers " version="1.0" license="MIT" app.name="hyperf-demo-api" -... - +# 其它内容省略 ``` ## 注意事项 -- Docker存储驱动限制:目前只支持overlay、overlay2,其他存储驱动需将日志所在目录mount到本地。然后改为收集宿主机 /logtail_host/your_path 下的日志即可。 +- Docker 存储驱动限制:目前只支持 `overlay`、`overlay2`,其他存储驱动需将日志所在目录 `mount` 到本地,然后改为收集宿主机 `~/logtail_host/your_path` 下的日志即可。 From 6f319d29404b141e615890dd9dbb22057cbfb3df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Wed, 4 Sep 2019 14:36:06 +0800 Subject: [PATCH 202/225] Update microservice.md --- doc/zh/microservice.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/microservice.md b/doc/zh/microservice.md index d8fa0ee94..787dd6f3f 100644 --- a/doc/zh/microservice.md +++ b/doc/zh/microservice.md @@ -52,4 +52,4 @@ 虽然 `微服务架构(Microservice)` 好处众多,但 **微服务不是银弹 !!!** ,您需要面对所有分布式系统都需要面对的复杂性,你可能需要在部署、测试和监控上做很多的工作,在服务间调用、服务的可靠性上做很多工作,甚至您还需要处理类似于 分布式事务 或者与 CAP 相关的问题。尽管 `Hyperf` 已经为您解决了许多的问题,但在实施 `微服务架构(Microservice)` 之前您的团队必须储备足够的分布式系统相关的知识体系,以面对很多您在 `单体架构(Monolithic architecture)` 下可能没有面临过甚至没有考虑过的问题。 -*| 本章节部分内容译自 Sam Newman 的 《Building Microservices 》* \ No newline at end of file +*| 本章节部分内容译自 Sam Newman 的 《Building Microservices》* From 9b347ed42716787b36620420e7dd73d8fa41a36e Mon Sep 17 00:00:00 2001 From: Bi Zhiming Date: Wed, 4 Sep 2019 15:03:28 +0800 Subject: [PATCH 203/225] =?UTF-8?q?snowflake=E9=A1=B9=E7=9B=AE=E5=8F=8A?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit snowflake项目及地址拼写错误 --- doc/zh/awesome-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/zh/awesome-components.md b/doc/zh/awesome-components.md index 3050f3a40..3e412fc69 100644 --- a/doc/zh/awesome-components.md +++ b/doc/zh/awesome-components.md @@ -87,7 +87,7 @@ ## ID 生成器 -- [hyperf/snawflake](https://github.com/hyperf-cloud/snawflake) Hyperf 官方提供的 Snowflake ID 生成器组件 (beta) +- [hyperf/snowflake](https://github.com/hyperf-cloud/snowflake) Hyperf 官方提供的 Snowflake ID 生成器组件 (beta) ## 文档生成 From 3cb93a68180c2f0140ddd84a9a4381e6f4e2ba71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 16:43:24 +0800 Subject: [PATCH 204/225] Fixed isFind is not defined. --- src/websocket-server/src/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/websocket-server/src/Server.php b/src/websocket-server/src/Server.php index 1ee927f2f..1903c2ca4 100644 --- a/src/websocket-server/src/Server.php +++ b/src/websocket-server/src/Server.php @@ -130,7 +130,7 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On /** @var Dispatched $dispatched */ $dispatched = $psr7Request->getAttribute(Dispatched::class); $middlewares = $this->middlewares; - if ($dispatched->isFind()) { + if ($dispatched->isFound()) { $registedMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod()); $middlewares = array_merge($middlewares, $registedMiddlewares); } From c893138729c1b791ad69e1d484d3381816c10f77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 17:19:29 +0800 Subject: [PATCH 205/225] Update RedisMetaGeneratorTest.php --- src/snowflake/tests/RedisMetaGeneratorTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/snowflake/tests/RedisMetaGeneratorTest.php b/src/snowflake/tests/RedisMetaGeneratorTest.php index 2e4d4bb5e..3d57d0776 100644 --- a/src/snowflake/tests/RedisMetaGeneratorTest.php +++ b/src/snowflake/tests/RedisMetaGeneratorTest.php @@ -17,6 +17,7 @@ use Hyperf\Contract\ConfigInterface; use Hyperf\Di\Container; use Hyperf\Pool\Channel; use Hyperf\Pool\PoolOption; +use Hyperf\Redis\Frequency; use Hyperf\Redis\Pool\PoolFactory; use Hyperf\Redis\Pool\RedisPool; use Hyperf\Redis\RedisProxy; @@ -178,6 +179,7 @@ class RedisMetaGeneratorTest extends TestCase $container->shouldReceive('make')->with(PoolOption::class, Mockery::any())->andReturnUsing(function ($class, $args) { return new PoolOption(...array_values($args)); }); + $container->shouldReceive('make')->with(Frequency::class, Mockery::any())->andReturn(new Frequency()); $container->shouldReceive('make')->with(RedisPool::class, Mockery::any())->andReturnUsing(function ($class, $args) use ($container) { return new RedisPool($container, $args['name']); }); From 4449f555acdd3ed82180c4255fea463f74d4c69f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 17:49:54 +0800 Subject: [PATCH 206/225] Changed db:model generate a singular class. --- src/database/src/Commands/ModelCommand.php | 7 +++++-- src/database/src/Commands/ModelOption.php | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/database/src/Commands/ModelCommand.php b/src/database/src/Commands/ModelCommand.php index cee45436a..239bf8ee5 100644 --- a/src/database/src/Commands/ModelCommand.php +++ b/src/database/src/Commands/ModelCommand.php @@ -94,7 +94,8 @@ class ModelCommand extends Command ->setInheritance($this->getOption('inheritance', 'commands.db:model.inheritance', $pool, 'Model')) ->setUses($this->getOption('uses', 'commands.db:model.uses', $pool, 'Hyperf\DbConnection\Model\Model')) ->setForceCasts($this->getOption('force-casts', 'commands.db:model.force_casts', $pool, false)) - ->setRefreshFillable($this->getOption('refresh-fillable', 'commands.db:model.refresh_fillable', $pool, false)); + ->setRefreshFillable($this->getOption('refresh-fillable', 'commands.db:model.refresh_fillable', $pool, false)) + ->setTableMapping($this->getOption('table-mapping', 'commands.db:model.table_mapping', $pool, [])); if ($table) { $this->createModel($table, $option); @@ -114,6 +115,7 @@ class ModelCommand extends Command $this->addOption('inheritance', 'i', InputOption::VALUE_OPTIONAL, 'The inheritance that you want the Model extends.'); $this->addOption('uses', 'U', InputOption::VALUE_OPTIONAL, 'The default class uses of the Model.'); $this->addOption('refresh-fillable', null, InputOption::VALUE_NONE, 'Whether generate fillable argement for model.'); + $this->addOption('table-mapping', 'M', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Table mappings for model.'); } protected function getSchemaBuilder(string $poolName): MySqlBuilder @@ -144,7 +146,8 @@ class ModelCommand extends Command $columns = $this->formatColumns($builder->getColumnTypeListing($table)); $project = new Project(); - $class = $project->namespace($option->getPath()) . Str::studly($table); + $class = $option->getTableMapping()[$table] ?? Str::studly(Str::singular($table)); + $class = $project->namespace($option->getPath()) . $class; $path = BASE_PATH . '/' . $project->path($class); if (! file_exists($path)) { diff --git a/src/database/src/Commands/ModelOption.php b/src/database/src/Commands/ModelOption.php index 9c2eba451..a1c0b8640 100644 --- a/src/database/src/Commands/ModelOption.php +++ b/src/database/src/Commands/ModelOption.php @@ -49,6 +49,11 @@ class ModelOption */ protected $refreshFillable; + /** + * @var array + */ + protected $tableMapping; + public function getPool(): string { return $this->pool; @@ -125,4 +130,19 @@ class ModelOption $this->refreshFillable = $refreshFillable; return $this; } + + public function getTableMapping(): array + { + return $this->tableMapping; + } + + public function setTableMapping(array $tableMapping): ModelOption + { + foreach ($tableMapping as $item) { + [$key, $name] = explode(':', $item); + $this->tableMapping[$key] = $name; + } + + return $this; + } } From ed54519db1bfe1696aa488262ab4acaf52bf05f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 17:52:34 +0800 Subject: [PATCH 207/225] Format code. --- CHANGELOG.md | 2 ++ src/database/src/Grammar.php | 2 +- src/database/src/Query/Grammars/Grammar.php | 4 ++-- src/database/src/Schema/Builder.php | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13d0f3b65..57ae52e35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,13 @@ - [#441](https://github.com/hyperf-cloud/hyperf/pull/441) Automatically close the spare redis client when it is used in low frequency. - [#455](https://github.com/hyperf-cloud/hyperf/pull/455) Added `download()` method of `Hyperf\HttpServer\Contract\ResponseInterface`. - [#500](https://github.com/hyperf-cloud/hyperf/pull/499) Added fluent method calls of `Hyperf\HttpServer\Contract\ResponseInterface`. +- [#523](https://github.com/hyperf-cloud/hyperf/pull/523) Added option `table-mapping` for command `db:model`. ## Changed - [#437](https://github.com/hyperf-cloud/hyperf/pull/437) Changed `Hyperf\Testing\Client` handle exception handlers instead of throw an exception directly. - [#463](https://github.com/hyperf-cloud/hyperf/pull/463) Simplify `container.php` and improve annotation caching mechanism. +- [#523](https://github.com/hyperf-cloud/hyperf/pull/523) Generate the singular class of an plural table. config/container.php diff --git a/src/database/src/Grammar.php b/src/database/src/Grammar.php index 36392cc13..d44c25c85 100755 --- a/src/database/src/Grammar.php +++ b/src/database/src/Grammar.php @@ -197,7 +197,7 @@ abstract class Grammar $segments[0] ) . ' as ' . $this->wrapValue( $segments[1] - ); + ); } /** diff --git a/src/database/src/Query/Grammars/Grammar.php b/src/database/src/Query/Grammars/Grammar.php index 1c8088325..af7fc4228 100755 --- a/src/database/src/Query/Grammars/Grammar.php +++ b/src/database/src/Query/Grammars/Grammar.php @@ -74,7 +74,7 @@ class Grammar extends BaseGrammar $sql = trim( $this->concatenate( $this->compileComponents($query) - ) + ) ); $query->columns = $original; @@ -770,7 +770,7 @@ class Grammar extends BaseGrammar return $not . $this->compileJsonContains( $where['column'], $this->parameter($where['value']) - ); + ); } /** diff --git a/src/database/src/Schema/Builder.php b/src/database/src/Schema/Builder.php index 5a1636507..48e33779e 100755 --- a/src/database/src/Schema/Builder.php +++ b/src/database/src/Schema/Builder.php @@ -81,7 +81,7 @@ class Builder return count($this->connection->selectFromWriteConnection( $this->grammar->compileTableExists(), [$table] - )) > 0; + )) > 0; } /** From dd089f95439ac40101b2109cc91b46b89b32347c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 17:59:58 +0800 Subject: [PATCH 208/225] Fixed config is not works. --- src/database/src/Commands/ModelCommand.php | 11 +++++++++-- src/database/src/Commands/ModelOption.php | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/database/src/Commands/ModelCommand.php b/src/database/src/Commands/ModelCommand.php index 239bf8ee5..5be70c3bd 100644 --- a/src/database/src/Commands/ModelCommand.php +++ b/src/database/src/Commands/ModelCommand.php @@ -95,7 +95,7 @@ class ModelCommand extends Command ->setUses($this->getOption('uses', 'commands.db:model.uses', $pool, 'Hyperf\DbConnection\Model\Model')) ->setForceCasts($this->getOption('force-casts', 'commands.db:model.force_casts', $pool, false)) ->setRefreshFillable($this->getOption('refresh-fillable', 'commands.db:model.refresh_fillable', $pool, false)) - ->setTableMapping($this->getOption('table-mapping', 'commands.db:model.table_mapping', $pool, [])); + ->setTableMapping($this->getOption('table-mapping', 'commands.db:model.table_mapping', $pool)); if ($table) { $this->createModel($table, $option); @@ -211,7 +211,14 @@ class ModelCommand extends Command protected function getOption(string $name, string $key, string $pool = 'default', $default = null) { $result = $this->input->getOption($name); - $nonInput = in_array($name, ['force-casts', 'refresh-fillable']) ? false : null; + $nonInput = null; + if (in_array($name, ['force-casts', 'refresh-fillable'])) { + $nonInput = false; + } + if (in_array($name, ['table-mapping'])) { + $nonInput = []; + } + if ($result === $nonInput) { $result = $this->config->get("databases.{$pool}.{$key}", $default); } diff --git a/src/database/src/Commands/ModelOption.php b/src/database/src/Commands/ModelOption.php index a1c0b8640..f3e2ecea2 100644 --- a/src/database/src/Commands/ModelOption.php +++ b/src/database/src/Commands/ModelOption.php @@ -52,7 +52,7 @@ class ModelOption /** * @var array */ - protected $tableMapping; + protected $tableMapping = []; public function getPool(): string { From 0eb826e896588fbc0b79f4eaea82e3c6c2c7d58e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Wed, 4 Sep 2019 18:41:53 +0800 Subject: [PATCH 209/225] Update .travis.yml --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 823d4d795..0e66ef926 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,15 +7,15 @@ matrix: - php: 7.2 env: SW_VERSION="4.3.6" - php: 7.2 - env: SW_VERSION="4.4.4" + env: SW_VERSION="4.4.5" - php: 7.3 env: SW_VERSION="4.3.6" - php: 7.3 - env: SW_VERSION="4.4.4" + env: SW_VERSION="4.4.5" - php: master env: SW_VERSION="4.3.6" - php: master - env: SW_VERSION="4.4.4" + env: SW_VERSION="4.4.5" allow_failures: - php: master From a17c0ad3306bfc33f2485907380aae87eb6036bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 5 Sep 2019 11:00:26 +0800 Subject: [PATCH 210/225] Format code. --- src/http-server/src/Response.php | 22 +--------------------- src/utils/src/Str.php | 4 ++-- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/src/http-server/src/Response.php b/src/http-server/src/Response.php index a03112c79..f8bc1033d 100644 --- a/src/http-server/src/Response.php +++ b/src/http-server/src/Response.php @@ -19,7 +19,6 @@ use Hyperf\HttpMessage\Stream\SwooleStream; use Hyperf\HttpServer\Contract\ResponseInterface; use Hyperf\HttpServer\Exception\Http\EncodingException; use Hyperf\HttpServer\Exception\Http\FileException; -use Hyperf\Utils\MimeTypeExtensionGuesser; use Hyperf\HttpServer\Exception\Http\InvalidResponseException; use Hyperf\Utils\ApplicationContext; use Hyperf\Utils\ClearStatCache; @@ -27,6 +26,7 @@ use Hyperf\Utils\Context; use Hyperf\Utils\Contracts\Arrayable; use Hyperf\Utils\Contracts\Jsonable; use Hyperf\Utils\Contracts\Xmlable; +use Hyperf\Utils\MimeTypeExtensionGuesser; use Hyperf\Utils\Str; use Hyperf\Utils\Traits\Macroable; use Psr\Http\Message\ResponseInterface as PsrResponseInterface; @@ -447,26 +447,6 @@ class Response implements PsrResponseInterface, ResponseInterface return $etag; } - /** - * Get ETag header according to the checksum of the file. - */ - protected function createEtag(\SplFileInfo $file, bool $weak = false): string - { - $etag = ''; - if ($weak) { - ClearStatCache::clear($file->getPathname()); - $lastModified = $file->getMTime(); - $filesize = $file->getSize(); - if (! $lastModified || ! $filesize) { - return $etag; - } - $etag = sprintf('W/"%x-%x"', $lastModified, $filesize); - } else { - $etag = md5_file($file->getPathname()); - } - return $etag; - } - /** * @param array|Arrayable|Jsonable $data * @throws EncodingException when the data encoding error diff --git a/src/utils/src/Str.php b/src/utils/src/Str.php index 7938d1622..e3a486951 100644 --- a/src/utils/src/Str.php +++ b/src/utils/src/Str.php @@ -324,7 +324,7 @@ class Str /** * Replace the first occurrence of a given value in the string. */ - public static function replaceFirst(string $search, string $replace, string $subject): string + public static function replaceFirst(string $search, string $replace, string $subject): string { if ($search == '') { return $subject; @@ -342,7 +342,7 @@ class Str /** * Replace the last occurrence of a given value in the string. */ - public static function replaceLast(string $search, string $replace, string $subject): string + public static function replaceLast(string $search, string $replace, string $subject): string { $position = strrpos($subject, $search); From 6618a0ff822c967dd5fd41f61d905c1b141fa533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 5 Sep 2019 11:07:53 +0800 Subject: [PATCH 211/225] Fixed typo. --- doc/zh/response.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/zh/response.md b/doc/zh/response.md index 7adde3d01..b95eda912 100644 --- a/doc/zh/response.md +++ b/doc/zh/response.md @@ -125,10 +125,10 @@ class IndexController ## 分块传输编码 Chunk -## 返回文件下载 +## 文件下载 `Hyperf\HttpServer\Contract\ResponseInterface` 提供了 `download(string $file, string $name = '')` 返回一个已设置下载文件状态的 `Psr7ResponseInterface` 对象。 -如果请求中带有 `if-match` 或 `if-none-match` 的请求头,Hyperf 也会跟根据协议标准与 `ETag` 进行比较,如果一致则会返回一个 `304` 状态码的响应。 +如果请求中带有 `if-match` 或 `if-none-match` 的请求头,Hyperf 也会根据协议标准与 `ETag` 进行比较,如果一致则会返回一个 `304` 状态码的响应。 `download` 方法: From 82cee05c03c87c9021891a9adc4c28ab93a609d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 5 Sep 2019 13:52:36 +0800 Subject: [PATCH 212/225] Update doc. --- doc/zh/imgs/snowflake.jpg | Bin 0 -> 27935 bytes doc/zh/snowflake.md | 4 ++++ doc/zh/summary.md | 1 + 3 files changed, 5 insertions(+) create mode 100644 doc/zh/imgs/snowflake.jpg diff --git a/doc/zh/imgs/snowflake.jpg b/doc/zh/imgs/snowflake.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5ccb4aaa61eca47c28cd59ccb3273f5fce80dfaf GIT binary patch literal 27935 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 `snowflake` 是 `Twitter` 开源的分布式 `ID生成算法`,结果是一个 `long` 型的 `ID`。其核心思想是:使用 `41bit` 作为毫秒数,`10bit` 作为机器的 `ID`(5 个 `bit` 是数据中心,5 个 `bit` 的机器 `ID`),`12bit` 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 `4096` 个 `ID`),最后还有一个符号位,永远是 `0`。 + +![snowflake](./imgs/snowflake.jpg) + ## 安装 ``` diff --git a/doc/zh/summary.md b/doc/zh/summary.md index 94b62331e..36f4b7f37 100644 --- a/doc/zh/summary.md +++ b/doc/zh/summary.md @@ -79,6 +79,7 @@ * [定时任务](zh/crontab.md) * [Task 机制](zh/task.md) * [枚举类](zh/constants.md) + * [Snowflake](zh/snowflake.md) * 应用部署 From d581e6d9c9564d9a495d884a5d2b72674914c7fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Thu, 5 Sep 2019 14:43:42 +0800 Subject: [PATCH 213/225] Update snowflake doc --- doc/zh/imgs/snowflake.jpeg | Bin 0 -> 30201 bytes doc/zh/imgs/snowflake.jpg | Bin 27935 -> 0 bytes doc/zh/snowflake.md | 24 ++++++++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 doc/zh/imgs/snowflake.jpeg delete mode 100644 doc/zh/imgs/snowflake.jpg diff --git a/doc/zh/imgs/snowflake.jpeg b/doc/zh/imgs/snowflake.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..b56b9868bb4501a2c8124db8687e705e637dfd40 GIT binary patch literal 30201 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 H^oaIvU5QRT literal 0 HcmV?d00001 diff --git a/doc/zh/imgs/snowflake.jpg b/doc/zh/imgs/snowflake.jpg deleted file mode 100644 index 5ccb4aaa61eca47c28cd59ccb3273f5fce80dfaf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27935 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 `snowflake` 是 `Twitter` 开源的分布式 `ID生成算法`,结果是一个 `long` 型的 `ID`。其核心思想是:使用 `41bit` 作为毫秒数,`10bit` 作为机器的 `ID`(5 个 `bit` 是数据中心,5 个 `bit` 的机器 `ID`),`12bit` 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 `4096` 个 `ID`),最后还有一个符号位,永远是 `0`。 +## 算法介绍 -![snowflake](./imgs/snowflake.jpg) +`Snowflake` 算法生成 `ID` 的结果是一个 `64bit` 大小的长整,它的结构如下图: + +![snowflake](./imgs/snowflake.jpeg) + +- `1位`,不用。 + - 二进制中最高位为符号位,我们生成的 `ID` 一般都是正整数,所以这个最高位固定是 0。 + +- `41位`,用来记录时间戳(毫秒)。 + - 41位可以表示 `2^41 - 1` 个数字。 + - 也就是说41位可以表示 `2^41 - 1` 个毫秒的值,转化成单位年则是 `(2^41 - 1) / (1000 * 60 * 60 * 24 * 365)` 约为 `69` 年。 + +- `10位`,用来记录工作机器 `ID`。 + - 可以部署在 `2^10` 共 `1024` 个节点,包括 `5` 位 `DatacenterId` 和 `5` 位 `WorkerId`。 + +- `12位`,序列号,用来记录同毫秒内产生的不同 `id`。 + - 12位(bit)可以表示的最大正整数是 `2^12 - 1` 共 `4095` 个数字,来表示同一机器同一时间截(毫秒)内产生的 `4095` 个 `ID` 序号。 + +`Snowflake` 可以保证: + + - 所有生成的 `ID` 按时间趋势递增。 + - 整个分布式系统内不会产生重复 `ID`(因为有 `DatacenterId` 和 `WorkerId` 来做区分)。 ## 安装 From 3d56db785a70c69ea50f7b1020447d167be20f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Thu, 5 Sep 2019 15:00:59 +0800 Subject: [PATCH 214/225] Update snowflake.md --- doc/zh/snowflake.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/zh/snowflake.md b/doc/zh/snowflake.md index 0bd84a930..3cb9f0fae 100644 --- a/doc/zh/snowflake.md +++ b/doc/zh/snowflake.md @@ -2,7 +2,7 @@ ## 算法介绍 -`Snowflake` 算法生成 `ID` 的结果是一个 `64bit` 大小的长整,它的结构如下图: +`Snowflake` 是由 Twitter 提出的一个分布式全局唯一 ID 生成算法,算法生成 `ID` 的结果是一个 `64bit` 大小的长整,标准算法下它的结构如下图: ![snowflake](./imgs/snowflake.jpeg) @@ -10,19 +10,21 @@ - 二进制中最高位为符号位,我们生成的 `ID` 一般都是正整数,所以这个最高位固定是 0。 - `41位`,用来记录时间戳(毫秒)。 - - 41位可以表示 `2^41 - 1` 个数字。 - - 也就是说41位可以表示 `2^41 - 1` 个毫秒的值,转化成单位年则是 `(2^41 - 1) / (1000 * 60 * 60 * 24 * 365)` 约为 `69` 年。 + - `41位` 可以表示 `2^41 - 1` 个数字。 + - 也就是说 `41位` 可以表示 `2^41 - 1` 个毫秒的值,转化成单位年则是 `(2^41 - 1) / (1000 * 60 * 60 * 24 * 365)` 约为 `69` 年。 - `10位`,用来记录工作机器 `ID`。 - 可以部署在 `2^10` 共 `1024` 个节点,包括 `5` 位 `DatacenterId` 和 `5` 位 `WorkerId`。 - `12位`,序列号,用来记录同毫秒内产生的不同 `id`。 - - 12位(bit)可以表示的最大正整数是 `2^12 - 1` 共 `4095` 个数字,来表示同一机器同一时间截(毫秒)内产生的 `4095` 个 `ID` 序号。 + - `12位` 可以表示的最大正整数是 `2^12 - 1` 共 `4095` 个数字,来表示同一机器同一时间截(毫秒)内产生的 `4095` 个 `ID` 序号。 `Snowflake` 可以保证: - 所有生成的 `ID` 按时间趋势递增。 - - 整个分布式系统内不会产生重复 `ID`(因为有 `DatacenterId` 和 `WorkerId` 来做区分)。 + - 整个分布式系统内不会产生重复 `ID`(因为有 `DatacenterId (5 bits)` 和 `WorkerId (5 bits)` 来做区分)。 + +Hyperf 的 [hyperf/snowflake](https://github.com/hyperf-cloud/snowflake) 组件在设计上提供了很好的可扩展性,允许您通过简单的扩展就能实现其它基于 Snowflake 的变体算法。 ## 安装 @@ -124,4 +126,4 @@ $userId = 20190620; $id = $generator->generate($userId); -``` \ No newline at end of file +``` From 853886ccf9a8c894c6cd7ea92c955468b6c63be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 6 Sep 2019 09:21:34 +0800 Subject: [PATCH 215/225] Upgrade swoole version to 4.4. --- .travis.yml | 12 +++--------- src/config-etcd/composer.json | 1 - src/etcd/composer.json | 1 - src/framework/composer.json | 2 +- src/server/composer.json | 1 - src/swoole-enterprise/composer.json | 1 - src/swoole-tracker/composer.json | 1 - src/utils/composer.json | 1 + src/utils/src/Functions.php | 7 +------ src/websocket-client/composer.json | 1 - src/websocket-server/composer.json | 1 - 11 files changed, 6 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 823d4d795..cb4aa2a78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,17 +5,11 @@ sudo: required matrix: include: - php: 7.2 - env: SW_VERSION="4.3.6" - - php: 7.2 - env: SW_VERSION="4.4.4" + env: SW_VERSION="4.4.5" - php: 7.3 - env: SW_VERSION="4.3.6" - - php: 7.3 - env: SW_VERSION="4.4.4" + env: SW_VERSION="4.4.5" - php: master - env: SW_VERSION="4.3.6" - - php: master - env: SW_VERSION="4.4.4" + env: SW_VERSION="4.4.5" allow_failures: - php: master diff --git a/src/config-etcd/composer.json b/src/config-etcd/composer.json index 66c454af4..699c4e9fc 100644 --- a/src/config-etcd/composer.json +++ b/src/config-etcd/composer.json @@ -21,7 +21,6 @@ }, "require": { "php": ">=7.2", - "ext-swoole": ">=4.3", "hyperf/utils": "~1.1.0", "hyperf/etcd": "~1.1.0" }, diff --git a/src/etcd/composer.json b/src/etcd/composer.json index ed4b66312..d066b19ff 100644 --- a/src/etcd/composer.json +++ b/src/etcd/composer.json @@ -20,7 +20,6 @@ }, "require": { "php": ">=7.2", - "ext-swoole": ">=4.3", "hyperf/utils": "~1.1.0" }, "require-dev": { diff --git a/src/framework/composer.json b/src/framework/composer.json index 463d10573..03ec78908 100644 --- a/src/framework/composer.json +++ b/src/framework/composer.json @@ -14,7 +14,7 @@ }, "require": { "php": ">=7.2", - "ext-swoole": ">=4.3", + "ext-swoole": ">=4.4", "fig/http-message-util": "^1.1.2", "hyperf/contract": "~1.1.0", "hyperf/utils": "~1.1.0", diff --git a/src/server/composer.json b/src/server/composer.json index 86a9d73e6..c83aa8191 100644 --- a/src/server/composer.json +++ b/src/server/composer.json @@ -12,7 +12,6 @@ }, "require": { "php": ">=7.2", - "ext-swoole": ">=4.3", "psr/container": "^1.0", "psr/log": "^1.0", "psr/event-dispatcher": "^1.0", diff --git a/src/swoole-enterprise/composer.json b/src/swoole-enterprise/composer.json index 73c8a2727..14d9054cb 100644 --- a/src/swoole-enterprise/composer.json +++ b/src/swoole-enterprise/composer.json @@ -12,7 +12,6 @@ }, "require": { "php": ">=7.2", - "ext-swoole": ">=4.3", "hyperf/contract": "~1.1.0", "hyperf/utils": "~1.1.0", "psr/container": "^1.0", diff --git a/src/swoole-tracker/composer.json b/src/swoole-tracker/composer.json index 6b65d3971..230279e61 100644 --- a/src/swoole-tracker/composer.json +++ b/src/swoole-tracker/composer.json @@ -12,7 +12,6 @@ }, "require": { "php": ">=7.2", - "ext-swoole": ">=4.3", "hyperf/contract": "~1.1.0", "hyperf/utils": "~1.1.0", "psr/container": "^1.0", diff --git a/src/utils/composer.json b/src/utils/composer.json index 1f707ed09..08e89704b 100644 --- a/src/utils/composer.json +++ b/src/utils/composer.json @@ -12,6 +12,7 @@ }, "require": { "php": ">=7.2", + "ext-swoole": ">=4.4", "doctrine/inflector": "^1.3", "hyperf/contract": "~1.1.0" }, diff --git a/src/utils/src/Functions.php b/src/utils/src/Functions.php index e8170893f..ecb0096eb 100644 --- a/src/utils/src/Functions.php +++ b/src/utils/src/Functions.php @@ -422,12 +422,7 @@ if (! function_exists('run')) { \Swoole\Runtime::enableCoroutine(true, $flags); - if (version_compare(swoole_version(), '4.4.0', '>=')) { - $result = \Swoole\Coroutine\Run($callback); - } else { - go($callback); - $result = true; - } + $result = \Swoole\Coroutine\Run($callback); \Swoole\Runtime::enableCoroutine(false); return $result; diff --git a/src/websocket-client/composer.json b/src/websocket-client/composer.json index d06c33141..47b15c275 100644 --- a/src/websocket-client/composer.json +++ b/src/websocket-client/composer.json @@ -12,7 +12,6 @@ }, "require": { "php": ">=7.2", - "ext-swoole": ">=4.3", "hyperf/contract": "~1.1.0", "hyperf/http-message": "~1.1.0", "hyperf/utils": "~1.1.0", diff --git a/src/websocket-server/composer.json b/src/websocket-server/composer.json index b4ae28152..f6d2f7d6f 100644 --- a/src/websocket-server/composer.json +++ b/src/websocket-server/composer.json @@ -12,7 +12,6 @@ }, "require": { "php": ">=7.2", - "ext-swoole": ">=4.3", "hyperf/contract": "~1.1.0", "hyperf/exception-handler": "~1.1.0", "hyperf/http-server": "~1.1.0", From acd48f64792432aa3c6807f35b2439170977aca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 6 Sep 2019 09:22:07 +0800 Subject: [PATCH 216/225] Set coroutine default value is true for hyperf command. --- src/command/src/Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/src/Command.php b/src/command/src/Command.php index 03327e3cc..a52d1dca3 100644 --- a/src/command/src/Command.php +++ b/src/command/src/Command.php @@ -55,7 +55,7 @@ abstract class Command extends SymfonyCommand * * @var bool */ - protected $coroutine = false; + protected $coroutine = true; /** * The mapping between human readable verbosity levels and Symfony's OutputInterface. From 9080a646d9c49638fcaa74a99c9ce607b70997d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Fri, 6 Sep 2019 09:31:46 +0800 Subject: [PATCH 217/225] Function 'run' only execute in non-coroutine environment. --- src/command/src/Command.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/command/src/Command.php b/src/command/src/Command.php index a52d1dca3..4f8956547 100644 --- a/src/command/src/Command.php +++ b/src/command/src/Command.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Hyperf\Command; use Hyperf\Utils\Contracts\Arrayable; +use Hyperf\Utils\Coroutine; use Hyperf\Utils\Str; use Symfony\Component\Console\Command\Command as SymfonyCommand; use Symfony\Component\Console\Formatter\OutputFormatterStyle; @@ -370,7 +371,7 @@ abstract class Command extends SymfonyCommand protected function execute(InputInterface $input, OutputInterface $output) { - if ($this->coroutine) { + if ($this->coroutine && ! Coroutine::inCoroutine()) { run(function () { call([$this, 'handle']); }); From 41d2d600d1980426c3abfdcacf645ef3986fe16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Mon, 9 Sep 2019 20:04:27 +0800 Subject: [PATCH 218/225] Update .travis.yml --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 846574729..cb4aa2a78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,11 +5,11 @@ sudo: required matrix: include: - php: 7.2 - env: SW_VERSION="4.4.6" + env: SW_VERSION="4.4.5" - php: 7.3 - env: SW_VERSION="4.4.6" + env: SW_VERSION="4.4.5" - php: master - env: SW_VERSION="4.4.6" + env: SW_VERSION="4.4.5" allow_failures: - php: master From 1bede0339f34b166bc1442a3491f267768110c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 10 Sep 2019 15:17:03 +0800 Subject: [PATCH 219/225] Update docker-swarm.md --- doc/zh/tutorial/docker-swarm.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/zh/tutorial/docker-swarm.md b/doc/zh/tutorial/docker-swarm.md index 0e52cbf3a..a441b93e5 100644 --- a/doc/zh/tutorial/docker-swarm.md +++ b/doc/zh/tutorial/docker-swarm.md @@ -8,6 +8,12 @@ curl -sSL https://get.daocloud.io/docker | sh ``` +修改文件 `/lib/systemd/system/docker.service`,允许使用 `TCP` 连接 `Docker` + +``` +ExecStart=/usr/bin/dockerd -H unix:// -H tcp://0.0.0.0:2375 +``` + ## 搭建自己的Gitlab ### 安装Gitlab From 607883c9a010b74d7354e46f16d1e6ddb238212d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 10 Sep 2019 16:26:54 +0800 Subject: [PATCH 220/225] Added function swoole_hook_flags. --- bootstrap.php | 1 + src/command/src/Command.php | 12 +++++++++++- src/server/src/Command/StartServer.php | 2 +- src/utils/src/Functions.php | 10 ++++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index 56c735571..eb424aa34 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -11,5 +11,6 @@ declare(strict_types=1); */ ! defined('BASE_PATH') && define('BASE_PATH', __DIR__); +! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL); require_once BASE_PATH . '/vendor/autoload.php'; diff --git a/src/command/src/Command.php b/src/command/src/Command.php index 4f8956547..66aa3f855 100644 --- a/src/command/src/Command.php +++ b/src/command/src/Command.php @@ -58,6 +58,11 @@ abstract class Command extends SymfonyCommand */ protected $coroutine = true; + /** + * @var int + */ + protected $hookFlags; + /** * The mapping between human readable verbosity levels and Symfony's OutputInterface. * @@ -77,6 +82,11 @@ abstract class Command extends SymfonyCommand if (! $name && $this->name) { $name = $this->name; } + + if (! is_int($this->hookFlags)) { + $this->hookFlags = swoole_hook_flags(); + } + parent::__construct($name); } @@ -374,7 +384,7 @@ abstract class Command extends SymfonyCommand if ($this->coroutine && ! Coroutine::inCoroutine()) { run(function () { call([$this, 'handle']); - }); + }, $this->hookFlags); return 0; } diff --git a/src/server/src/Command/StartServer.php b/src/server/src/Command/StartServer.php index da5c68fa0..5a3e2cb89 100644 --- a/src/server/src/Command/StartServer.php +++ b/src/server/src/Command/StartServer.php @@ -42,7 +42,7 @@ class StartServer extends SymfonyCommand protected function execute(InputInterface $input, OutputInterface $output) { - \Swoole\Runtime::enableCoroutine(true); + \Swoole\Runtime::enableCoroutine(true, swoole_hook_flags()); $this->checkEnvironment($output); diff --git a/src/utils/src/Functions.php b/src/utils/src/Functions.php index ecb0096eb..1081c7cda 100644 --- a/src/utils/src/Functions.php +++ b/src/utils/src/Functions.php @@ -428,3 +428,13 @@ if (! function_exists('run')) { return $result; } } + +if (! function_exists('swoole_hook_flags')) { + /** + * Return the default swoole hook flags, you can rewrite it by defining `SWOOLE_HOOK_FLAGS`. + */ + function swoole_hook_flags(): int + { + return defined('SWOOLE_HOOK_FLAGS') ? SWOOLE_HOOK_FLAGS : SWOOLE_HOOK_ALL; + } +} From b7394e79d50a673816627e44c5342c1d2088aca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 10 Sep 2019 16:31:10 +0800 Subject: [PATCH 221/225] Update FunctionTest.php --- src/utils/tests/FunctionTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/utils/tests/FunctionTest.php b/src/utils/tests/FunctionTest.php index 29d957658..f750bd045 100644 --- a/src/utils/tests/FunctionTest.php +++ b/src/utils/tests/FunctionTest.php @@ -105,4 +105,9 @@ class FunctionTest extends TestCase $this->assertSame(1, $result); } } + + public function testSwooleHookFlags() + { + $this->assertSame(SWOOLE_HOOK_ALL, swoole_hook_flags()); + } } From ca05d123a9e4677401cc83b3636817507e027ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 10 Sep 2019 17:13:55 +0800 Subject: [PATCH 222/225] Added testing. --- composer.json | 6 +++- src/command/.gitattributes | 1 + src/command/composer.json | 1 + .../Command/DefaultSwooleFlagsCommand.php | 27 +++++++++++++++ .../tests/Command/SwooleFlagsCommand.php | 29 ++++++++++++++++ src/command/tests/CommandTest.php | 33 +++++++++++++++++++ 6 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/command/.gitattributes create mode 100644 src/command/tests/Command/DefaultSwooleFlagsCommand.php create mode 100644 src/command/tests/Command/SwooleFlagsCommand.php create mode 100644 src/command/tests/CommandTest.php diff --git a/composer.json b/composer.json index 380b61523..cb55c59a6 100644 --- a/composer.json +++ b/composer.json @@ -157,6 +157,7 @@ "Hyperf\\ServiceGovernance\\": "src/service-governance/src/", "Hyperf\\Snowflake\\": "src/snowflake/src/", "Hyperf\\Swagger\\": "src/swagger/src/", + "Hyperf\\SwooleEnterprise\\": "src/swoole-enterprise/src/", "Hyperf\\SwooleTracker\\": "src/swoole-tracker/src/", "Hyperf\\Task\\": "src/task/src/", "Hyperf\\Testing\\": "src/testing/src/", @@ -175,6 +176,7 @@ "HyperfTest\\Amqp\\": "src/amqp/tests/", "HyperfTest\\AsyncQueue\\": "src/async-queue/tests/", "HyperfTest\\Cache\\": "src/cache/tests/", + "HyperfTest\\Command\\": "src/command/tests/", "HyperfTest\\ConfigAliyunAcm\\": "src/config-aliyun-acm/tests/", "HyperfTest\\ConfigApollo\\": "src/config-apollo/tests/", "HyperfTest\\ConfigEtcd\\": "src/config-etcd/tests/", @@ -229,6 +231,7 @@ "Hyperf\\ConfigApollo\\ConfigProvider", "Hyperf\\ConfigEtcd\\ConfigProvider", "Hyperf\\Config\\ConfigProvider", + "Hyperf\\Constants\\ConfigProvider", "Hyperf\\Consul\\ConfigProvider", "Hyperf\\Crontab\\ConfigProvider", "Hyperf\\DbConnection\\ConfigProvider", @@ -260,6 +263,7 @@ "Hyperf\\ServiceGovernance\\ConfigProvider", "Hyperf\\Snowflake\\ConfigProvider", "Hyperf\\Swagger\\ConfigProvider", + "Hyperf\\SwooleEnterprise\\ConfigProvider", "Hyperf\\SwooleTracker\\ConfigProvider", "Hyperf\\Task\\ConfigProvider", "Hyperf\\Tracer\\ConfigProvider", @@ -282,4 +286,4 @@ }, "minimum-stability": "dev", "prefer-stable": true -} +} \ No newline at end of file diff --git a/src/command/.gitattributes b/src/command/.gitattributes new file mode 100644 index 000000000..bdd4ea29c --- /dev/null +++ b/src/command/.gitattributes @@ -0,0 +1 @@ +/tests export-ignore \ No newline at end of file diff --git a/src/command/composer.json b/src/command/composer.json index 531e0fee5..b6696b2bb 100644 --- a/src/command/composer.json +++ b/src/command/composer.json @@ -15,6 +15,7 @@ }, "autoload-dev": { "psr-4": { + "HyperfTest\\Command\\": "tests/" } }, "require": { diff --git a/src/command/tests/Command/DefaultSwooleFlagsCommand.php b/src/command/tests/Command/DefaultSwooleFlagsCommand.php new file mode 100644 index 000000000..ba9f0d276 --- /dev/null +++ b/src/command/tests/Command/DefaultSwooleFlagsCommand.php @@ -0,0 +1,27 @@ +hookFlags; + } +} diff --git a/src/command/tests/Command/SwooleFlagsCommand.php b/src/command/tests/Command/SwooleFlagsCommand.php new file mode 100644 index 000000000..dc34775ed --- /dev/null +++ b/src/command/tests/Command/SwooleFlagsCommand.php @@ -0,0 +1,29 @@ +hookFlags; + } +} diff --git a/src/command/tests/CommandTest.php b/src/command/tests/CommandTest.php new file mode 100644 index 000000000..0b3df2811 --- /dev/null +++ b/src/command/tests/CommandTest.php @@ -0,0 +1,33 @@ +assertSame(SWOOLE_HOOK_ALL, $command->getHookFlags()); + + $command = new SwooleFlagsCommand('test:demo2'); + $this->assertSame(SWOOLE_HOOK_ALL | SWOOLE_HOOK_CURL, $command->getHookFlags()); + } +} From 630e01a88572b6718315b7fbcb670ea8f2510ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=93=AD=E6=98=95?= <715557344@qq.com> Date: Tue, 10 Sep 2019 17:18:59 +0800 Subject: [PATCH 223/225] Update CHANGELOG.md --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3050c11f..866bb5589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,35 @@ - [#455](https://github.com/hyperf-cloud/hyperf/pull/455) Added `download()` method of `Hyperf\HttpServer\Contract\ResponseInterface`. - [#500](https://github.com/hyperf-cloud/hyperf/pull/499) Added fluent method calls of `Hyperf\HttpServer\Contract\ResponseInterface`. - [#523](https://github.com/hyperf-cloud/hyperf/pull/523) Added option `table-mapping` for command `db:model`. +- [#555](https://github.com/hyperf-cloud/hyperf/pull/555) Added function `swoole_hook_flags` to get the hook flags by defining `SWOOLE_HOOK_FLAGS`. + +bin/hyperf.php + +```php +#!/usr/bin/env php +get(\Hyperf\Contract\ApplicationInterface::class); + $application->run(); +})(); + +``` ## Changed From d6ebc0c6e200b275ae149ae9ca0ac8cc3897eeae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=9C=9D=E6=99=96?= Date: Tue, 10 Sep 2019 17:24:06 +0800 Subject: [PATCH 224/225] Update CHANGELOG.md --- CHANGELOG.md | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 866bb5589..f8b96c041 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,38 +7,9 @@ - [#418](https://github.com/hyperf-cloud/hyperf/pull/418) Allows send WebSocket message to any fd in current server, even the worker process does not hold the fd - [#420](https://github.com/hyperf-cloud/hyperf/pull/420) Added listener for model. - [#441](https://github.com/hyperf-cloud/hyperf/pull/441) Automatically close the spare redis client when it is used in low frequency. -- [#455](https://github.com/hyperf-cloud/hyperf/pull/455) Added `download()` method of `Hyperf\HttpServer\Contract\ResponseInterface`. - [#500](https://github.com/hyperf-cloud/hyperf/pull/499) Added fluent method calls of `Hyperf\HttpServer\Contract\ResponseInterface`. - [#523](https://github.com/hyperf-cloud/hyperf/pull/523) Added option `table-mapping` for command `db:model`. -- [#555](https://github.com/hyperf-cloud/hyperf/pull/555) Added function `swoole_hook_flags` to get the hook flags by defining `SWOOLE_HOOK_FLAGS`. - -bin/hyperf.php - -```php -#!/usr/bin/env php -get(\Hyperf\Contract\ApplicationInterface::class); - $application->run(); -})(); - -``` +- [#555](https://github.com/hyperf-cloud/hyperf/pull/555) Added global function `swoole_hook_flags` to get the hook flags by constant `SWOOLE_HOOK_FLAGS`, and you could define in `bin/hyperf.php` via `! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);` to define the constant. ## Changed From af7f106b1724b1e0d26b5e935800272d1faa1b42 Mon Sep 17 00:00:00 2001 From: WanglinGuo <47772108+WanglinGuo@users.noreply.github.com> Date: Wed, 11 Sep 2019 11:00:56 +0800 Subject: [PATCH 225/225] =?UTF-8?q?hyperf/logger=20=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E4=BF=AE=E6=94=B9=20(#561)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/zh/logger.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/zh/logger.md b/doc/zh/logger.md index 7e1ad4269..a62fe5171 100644 --- a/doc/zh/logger.md +++ b/doc/zh/logger.md @@ -58,8 +58,8 @@ class DemoService public function __construct(LoggerFactory $loggerFactory) { - // default 对应 config/autoload/logger.php 内的 key - $this->logger = $loggerFactory->get('default'); + // 第一个参数对应日志的 name, 第二个参数对应 config/autoload/logger.php 内的 key + $this->logger = $loggerFactory->get('log', 'default'); } public function method()