first commit
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
composer.lock
|
||||
vendor
|
||||
vendor/
|
||||
.idea
|
||||
.idea/
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
# webman-framework
|
||||
Note: This repository is the core code of the webman framework. If you want to build an application using webman, visit the main [webman](https://github.com/walkor/webman) repository.
|
||||
|
||||
## LICENSE
|
||||
MIT
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "workerman/webman-framework",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"high performance",
|
||||
"http service"
|
||||
],
|
||||
"homepage": "https://www.workerman.net",
|
||||
"license": "MIT",
|
||||
"description": "High performance HTTP Service Framework.",
|
||||
"authors": [
|
||||
{
|
||||
"name": "walkor",
|
||||
"email": "walkor@workerman.net",
|
||||
"homepage": "https://www.workerman.net",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"email": "walkor@workerman.net",
|
||||
"issues": "https://github.com/walkor/webman/issues",
|
||||
"forum": "https://wenda.workerman.net/",
|
||||
"wiki": "https://doc.workerman.net/",
|
||||
"source": "https://github.com/walkor/webman-framework"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"workerman/workerman": "^4.0.4",
|
||||
"nikic/fast-route": "^1.3",
|
||||
"psr/container": ">=1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-event": "For better performance. "
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webman\\": "./src",
|
||||
"support\\": "./src/support",
|
||||
"Support\\": "./src/support",
|
||||
"Support\\Bootstrap\\": "./src/support/bootstrap",
|
||||
"Support\\Exception\\": "./src/support/exception",
|
||||
"Support\\View\\": "./src/support/view"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
+863
@@ -0,0 +1,863 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman;
|
||||
|
||||
use Closure;
|
||||
use FastRoute\Dispatcher;
|
||||
use Monolog\Logger;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use ReflectionFunction;
|
||||
use ReflectionFunctionAbstract;
|
||||
use ReflectionMethod;
|
||||
use Throwable;
|
||||
use Webman\Exception\ExceptionHandler;
|
||||
use Webman\Exception\ExceptionHandlerInterface;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
use Webman\Route\Route as RouteObject;
|
||||
use Workerman\Connection\TcpConnection;
|
||||
use Workerman\Protocols\Http;
|
||||
use Workerman\Worker;
|
||||
|
||||
/**
|
||||
* Class App
|
||||
* @package Webman
|
||||
*/
|
||||
class App
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_callbacks = [];
|
||||
|
||||
/**
|
||||
* @var Worker
|
||||
*/
|
||||
protected static $_worker = null;
|
||||
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected static $_container = null;
|
||||
|
||||
/**
|
||||
* @var Logger
|
||||
*/
|
||||
protected static $_logger = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $_appPath = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $_publicPath = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $_configPath = '';
|
||||
|
||||
/**
|
||||
* @var TcpConnection
|
||||
*/
|
||||
protected static $_connection = null;
|
||||
|
||||
/**
|
||||
* @var Request
|
||||
*/
|
||||
protected static $_request = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $_requestClass = '';
|
||||
|
||||
/**
|
||||
* App constructor.
|
||||
*
|
||||
* @param string $request_class
|
||||
* @param Logger $logger
|
||||
* @param string $app_path
|
||||
* @param string $public_path
|
||||
*/
|
||||
public function __construct(string $request_class, Logger $logger, string $app_path, string $public_path)
|
||||
{
|
||||
static::$_requestClass = $request_class;
|
||||
static::$_logger = $logger;
|
||||
static::$_publicPath = $public_path;
|
||||
static::$_appPath = $app_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TcpConnection $connection
|
||||
* @param Request $request
|
||||
* @return null
|
||||
*/
|
||||
public function onMessage($connection, $request)
|
||||
{
|
||||
try {
|
||||
static::$_request = $request;
|
||||
static::$_connection = $connection;
|
||||
$path = $request->path();
|
||||
$key = $request->method() . $path;
|
||||
if (isset(static::$_callbacks[$key])) {
|
||||
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
|
||||
static::send($connection, $callback($request), $request);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
static::unsafeUri($connection, $path, $request) ||
|
||||
static::findFile($connection, $path, $key, $request) ||
|
||||
static::findRoute($connection, $path, $key, $request)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$controller_and_action = static::parseControllerAction($path);
|
||||
$plugin = $controller_and_action['plugin'] ?? static::getPluginByPath($path);
|
||||
if (!$controller_and_action || Route::hasDisableDefaultRoute($plugin)) {
|
||||
$callback = static::getFallback($plugin);
|
||||
$request->app = $request->controller = $request->action = '';
|
||||
static::send($connection, $callback($request), $request);
|
||||
return null;
|
||||
}
|
||||
$app = $controller_and_action['app'];
|
||||
$controller = $controller_and_action['controller'];
|
||||
$action = $controller_and_action['action'];
|
||||
$callback = static::getCallback($plugin, $app, [$controller, $action]);
|
||||
static::collectCallbacks($key, [$callback, $plugin, $app, $controller, $action, null]);
|
||||
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
|
||||
static::send($connection, $callback($request), $request);
|
||||
} catch (Throwable $e) {
|
||||
static::send($connection, static::exceptionResponse($e, $request), $request);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $worker
|
||||
* @return void
|
||||
*/
|
||||
public function onWorkerStart($worker)
|
||||
{
|
||||
static::$_worker = $worker;
|
||||
Http::requestClass(static::$_requestClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
protected static function collectCallbacks(string $key, array $data)
|
||||
{
|
||||
static::$_callbacks[$key] = $data;
|
||||
if (\count(static::$_callbacks) >= 1024) {
|
||||
unset(static::$_callbacks[\key(static::$_callbacks)]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TcpConnection $connection
|
||||
* @param string $path
|
||||
* @param $request
|
||||
* @return bool
|
||||
*/
|
||||
protected static function unsafeUri(TcpConnection $connection, string $path, $request): bool
|
||||
{
|
||||
if (
|
||||
!$path ||
|
||||
\strpos($path, '..') !== false ||
|
||||
\strpos($path, "\\") !== false ||
|
||||
\strpos($path, "\0") !== false
|
||||
) {
|
||||
$callback = static::getFallback();
|
||||
$request->plugin = $request->app = $request->controller = $request->action = '';
|
||||
static::send($connection, $callback($request), $request);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plugin
|
||||
* @return Closure
|
||||
*/
|
||||
protected static function getFallback(string $plugin = ''): Closure
|
||||
{
|
||||
// when route, controller and action not found, try to use Route::fallback
|
||||
return Route::getFallback($plugin) ?: function () {
|
||||
try {
|
||||
$notFoundContent = \file_get_contents(static::$_publicPath . '/404.html');
|
||||
} catch (Throwable $e) {
|
||||
$notFoundContent = '404 Not Found';
|
||||
}
|
||||
return new Response(404, [], $notFoundContent);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Throwable $e
|
||||
* @param $request
|
||||
* @return Response
|
||||
*/
|
||||
protected static function exceptionResponse(Throwable $e, $request)
|
||||
{
|
||||
try {
|
||||
$app = $request->app ?: '';
|
||||
$plugin = $request->plugin ?: '';
|
||||
$exception_config = static::config($plugin, 'exception');
|
||||
$default_exception = $exception_config[''] ?? ExceptionHandler::class;
|
||||
$exception_handler_class = $exception_config[$app] ?? $default_exception;
|
||||
|
||||
/** @var ExceptionHandlerInterface $exception_handler */
|
||||
$exception_handler = static::container($plugin)->make($exception_handler_class, [
|
||||
'logger' => static::$_logger,
|
||||
'debug' => static::config($plugin, 'app.debug')
|
||||
]);
|
||||
$exception_handler->report($e);
|
||||
$response = $exception_handler->render($request, $e);
|
||||
$response->exception($e);
|
||||
return $response;
|
||||
} catch (Throwable $e) {
|
||||
$response = new Response(500, [], static::config($plugin ?? '', 'app.debug') ? (string)$e : $e->getMessage());
|
||||
$response->exception($e);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $app
|
||||
* @param $call
|
||||
* @param array|null $args
|
||||
* @param bool $with_global_middleware
|
||||
* @param RouteObject $route
|
||||
* @return callable
|
||||
*/
|
||||
protected static function getCallback(string $plugin, string $app, $call, array $args = null, bool $with_global_middleware = true, RouteObject $route = null)
|
||||
{
|
||||
$args = $args === null ? null : \array_values($args);
|
||||
$middlewares = [];
|
||||
if ($route) {
|
||||
$route_middlewares = \array_reverse($route->getMiddleware());
|
||||
foreach ($route_middlewares as $class_name) {
|
||||
$middlewares[] = [$class_name, 'process'];
|
||||
}
|
||||
}
|
||||
$middlewares = \array_merge($middlewares, Middleware::getMiddleware($plugin, $app, $with_global_middleware));
|
||||
|
||||
foreach ($middlewares as $key => $item) {
|
||||
$middleware = $item[0];
|
||||
if (is_string($middleware)) {
|
||||
$middleware = static::container($plugin)->get($middleware);
|
||||
} elseif ($middleware instanceof \Closure) {
|
||||
$middleware = call_user_func($middleware, static::container($plugin));
|
||||
}
|
||||
if (!$middleware instanceof MiddlewareInterface) {
|
||||
throw new \InvalidArgumentException('Not support middleware type');
|
||||
}
|
||||
$middlewares[$key][0] = $middleware;
|
||||
}
|
||||
|
||||
$need_inject = static::isNeedInject($call, $args);
|
||||
if (\is_array($call) && \is_string($call[0])) {
|
||||
$controller_reuse = static::config($plugin, 'app.controller_reuse', true);
|
||||
if (!$controller_reuse) {
|
||||
if ($need_inject) {
|
||||
$call = function ($request, ...$args) use ($call, $plugin) {
|
||||
$call[0] = static::container($plugin)->make($call[0]);
|
||||
$reflector = static::getReflector($call);
|
||||
$args = static::resolveMethodDependencies($plugin, $request, $args, $reflector);
|
||||
return $call(...$args);
|
||||
};
|
||||
$need_inject = false;
|
||||
} else {
|
||||
$call = function ($request, ...$args) use ($call, $plugin) {
|
||||
$call[0] = static::container($plugin)->make($call[0]);
|
||||
return $call($request, ...$args);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
$call[0] = static::container($plugin)->get($call[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($need_inject) {
|
||||
$call = static::resolveInject($plugin, $call);
|
||||
}
|
||||
|
||||
if ($middlewares) {
|
||||
$callback = \array_reduce($middlewares, function ($carry, $pipe) {
|
||||
return function ($request) use ($carry, $pipe) {
|
||||
try {
|
||||
return $pipe($request, $carry);
|
||||
} catch (Throwable $e) {
|
||||
return static::exceptionResponse($e, $request);
|
||||
}
|
||||
};
|
||||
}, function ($request) use ($call, $args) {
|
||||
try {
|
||||
if ($args === null) {
|
||||
$response = $call($request);
|
||||
} else {
|
||||
$response = $call($request, ...$args);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
return static::exceptionResponse($e, $request);
|
||||
}
|
||||
if (!$response instanceof Response) {
|
||||
if (\is_array($response)) {
|
||||
$response = 'Array';
|
||||
}
|
||||
$response = new Response(200, [], $response);
|
||||
}
|
||||
return $response;
|
||||
});
|
||||
} else {
|
||||
if ($args === null) {
|
||||
$callback = $call;
|
||||
} else {
|
||||
$callback = function ($request) use ($call, $args) {
|
||||
return $call($request, ...$args);
|
||||
};
|
||||
}
|
||||
}
|
||||
return $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plugin
|
||||
* @param array|Closure $call
|
||||
* @param null|array $args
|
||||
* @return Closure
|
||||
* @see Dependency injection through reflection information
|
||||
*/
|
||||
protected static function resolveInject(string $plugin, $call)
|
||||
{
|
||||
return function (Request $request, ...$args) use ($plugin, $call) {
|
||||
$reflector = static::getReflector($call);
|
||||
$args = static::resolveMethodDependencies($plugin, $request, $args, $reflector);
|
||||
return $call(...$args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether inject is required
|
||||
*
|
||||
* @param $call
|
||||
* @param $args
|
||||
* @return bool
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected static function isNeedInject($call, $args)
|
||||
{
|
||||
if (\is_array($call) && !\method_exists($call[0], $call[1])) {
|
||||
return false;
|
||||
}
|
||||
$args = $args ?: [];
|
||||
$reflector = static::getReflector($call);
|
||||
$reflection_parameters = $reflector->getParameters();
|
||||
if (!$reflection_parameters) {
|
||||
return false;
|
||||
}
|
||||
$first_parameter = \current($reflection_parameters);
|
||||
unset($reflection_parameters[\key($reflection_parameters)]);
|
||||
$adapters_list = ['int', 'string', 'bool', 'array', 'object', 'float', 'mixed', 'resource'];
|
||||
foreach ($reflection_parameters as $parameter) {
|
||||
if ($parameter->hasType() && !\in_array($parameter->getType()->getName(), $adapters_list)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!$first_parameter->hasType()) {
|
||||
if (\count($args) <= count($reflection_parameters)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} elseif (!\is_a(static::$_request, $first_parameter->getType()->getName())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reflector.
|
||||
*
|
||||
* @param $call
|
||||
* @return ReflectionFunction|ReflectionMethod
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected static function getReflector($call)
|
||||
{
|
||||
if ($call instanceof Closure || \is_string($call)) {
|
||||
return new ReflectionFunction($call);
|
||||
}
|
||||
return new ReflectionMethod($call[0], $call[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return dependent parameters
|
||||
*
|
||||
* @param string $plugin
|
||||
* @param Request $request
|
||||
* @param array $args
|
||||
* @param ReflectionFunctionAbstract $reflector
|
||||
* @return array
|
||||
*/
|
||||
protected static function resolveMethodDependencies(string $plugin, Request $request, array $args, ReflectionFunctionAbstract $reflector)
|
||||
{
|
||||
// Specification parameter information
|
||||
$args = \array_values($args);
|
||||
$parameters = [];
|
||||
// An array of reflection classes for loop parameters, with each $parameter representing a reflection object of parameters
|
||||
foreach ($reflector->getParameters() as $parameter) {
|
||||
// Parameter quota consumption
|
||||
if ($parameter->hasType()) {
|
||||
$name = $parameter->getType()->getName();
|
||||
switch ($name) {
|
||||
case 'int':
|
||||
case 'string':
|
||||
case 'bool':
|
||||
case 'array':
|
||||
case 'object':
|
||||
case 'float':
|
||||
case 'mixed':
|
||||
case 'resource':
|
||||
goto _else;
|
||||
default:
|
||||
if (\is_a(static::$_request, $name)) {
|
||||
//Inject Request
|
||||
$parameters[] = $request;
|
||||
} else {
|
||||
$parameters[] = static::container($plugin)->make($name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_else:
|
||||
// The variable parameter
|
||||
if (null !== \key($args)) {
|
||||
$parameters[] = \current($args);
|
||||
} else {
|
||||
// Indicates whether the current parameter has a default value. If yes, return true
|
||||
$parameters[] = $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null;
|
||||
}
|
||||
// Quota of consumption variables
|
||||
\next($args);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the result of parameters replacement
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plugin
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public static function container(string $plugin = '')
|
||||
{
|
||||
return static::config($plugin, 'container');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Request|\support\Request
|
||||
*/
|
||||
public static function request()
|
||||
{
|
||||
return static::$_request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TcpConnection
|
||||
*/
|
||||
public static function connection()
|
||||
{
|
||||
return static::$_connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Worker
|
||||
*/
|
||||
public static function worker()
|
||||
{
|
||||
return static::$_worker;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TcpConnection $connection
|
||||
* @param string $path
|
||||
* @param string $key
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
protected static function findRoute(TcpConnection $connection, string $path, string $key, $request)
|
||||
{
|
||||
$ret = Route::dispatch($request->method(), $path);
|
||||
if ($ret[0] === Dispatcher::FOUND) {
|
||||
$ret[0] = 'route';
|
||||
$callback = $ret[1]['callback'];
|
||||
$route = clone $ret[1]['route'];
|
||||
$app = $controller = $action = '';
|
||||
$args = !empty($ret[2]) ? $ret[2] : null;
|
||||
if ($args) {
|
||||
$route->setParams($args);
|
||||
}
|
||||
if (\is_array($callback)) {
|
||||
$controller = $callback[0];
|
||||
$plugin = static::getPluginByClass($controller);
|
||||
$app = static::getAppByController($controller);
|
||||
$action = static::getRealMethod($controller, $callback[1]) ?? '';
|
||||
} else {
|
||||
$plugin = static::getPluginByPath($path);
|
||||
}
|
||||
$callback = static::getCallback($plugin, $app, $callback, $args, true, $route);
|
||||
static::collectCallbacks($key, [$callback, $plugin, $app, $controller ?: '', $action, $route]);
|
||||
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
|
||||
static::send($connection, $callback($request), $request);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TcpConnection $connection
|
||||
* @param string $path
|
||||
* @param string $key
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
protected static function findFile(TcpConnection $connection, string $path, string $key, $request): bool
|
||||
{
|
||||
if (preg_match('/%[0-9a-f]{2}/i', $path)) {
|
||||
$path = urldecode($path);
|
||||
if (static::unsafeUri($connection, $path, $request)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$path_explodes = \explode('/', trim($path, '/'));
|
||||
$plugin = '';
|
||||
if (isset($path_explodes[1]) && $path_explodes[0] === 'app') {
|
||||
$public_dir = BASE_PATH . "/plugin/{$path_explodes[1]}/public";
|
||||
$plugin = $path_explodes[1];
|
||||
$path = \substr($path, strlen("/app/{$path_explodes[1]}/"));
|
||||
} else {
|
||||
$public_dir = static::$_publicPath;
|
||||
}
|
||||
$file = "$public_dir/$path";
|
||||
if (!\is_file($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (\pathinfo($file, PATHINFO_EXTENSION) === 'php') {
|
||||
if (!static::config($plugin, 'app.support_php_files', false)) {
|
||||
return false;
|
||||
}
|
||||
static::collectCallbacks($key, [function () use ($file) {
|
||||
return static::execPhpFile($file);
|
||||
}, '', '', '', '', null]);
|
||||
[, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
|
||||
static::send($connection, static::execPhpFile($file), $request);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!static::config($plugin, 'static.enable', false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static::collectCallbacks($key, [static::getCallback($plugin, '__static__', function ($request) use ($file, $plugin) {
|
||||
\clearstatcache(true, $file);
|
||||
if (!\is_file($file)) {
|
||||
$callback = static::getFallback($plugin);
|
||||
return $callback($request);
|
||||
}
|
||||
return (new Response())->file($file);
|
||||
}, null, false), '', '', '', '', null]);
|
||||
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
|
||||
static::send($connection, $callback($request), $request);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TcpConnection $connection
|
||||
* @param Response $response
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
protected static function send(TcpConnection $connection, $response, $request)
|
||||
{
|
||||
$keep_alive = $request->header('connection');
|
||||
static::$_request = static::$_connection = null;
|
||||
if (($keep_alive === null && $request->protocolVersion() === '1.1')
|
||||
|| $keep_alive === 'keep-alive' || $keep_alive === 'Keep-Alive'
|
||||
) {
|
||||
$connection->send($response);
|
||||
return;
|
||||
}
|
||||
$connection->close($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return array|false
|
||||
* @throws \Psr\Container\ContainerExceptionInterface
|
||||
* @throws \Psr\Container\NotFoundExceptionInterface
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected static function parseControllerAction(string $path)
|
||||
{
|
||||
$path = \str_replace('-', '', $path);
|
||||
$path_explode = \explode('/', trim($path, '/'));
|
||||
$is_plugin = isset($path_explode[1]) && $path_explode[0] === 'app';
|
||||
$config_prefix = $is_plugin ? "plugin.{$path_explode[1]}." : '';
|
||||
$path_prefix = $is_plugin ? "/app/{$path_explode[1]}" : '';
|
||||
$class_prefix = $is_plugin ? "plugin\\{$path_explode[1]}" : '';
|
||||
$suffix = Config::get("{$config_prefix}app.controller_suffix", '');
|
||||
$relative_path = \trim(substr($path, strlen($path_prefix)), '/');
|
||||
$path_explode = $relative_path ? \explode('/', $relative_path) : [];
|
||||
|
||||
$action = 'index';
|
||||
if ($controller_action = static::guessControllerAction($path_explode, $action, $suffix, $class_prefix)) {
|
||||
return $controller_action;
|
||||
}
|
||||
$action = \end($path_explode);
|
||||
unset($path_explode[count($path_explode) - 1]);
|
||||
return static::guessControllerAction($path_explode, $action, $suffix, $class_prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path_explode
|
||||
* @param $action
|
||||
* @param $suffix
|
||||
* @param $class_prefix
|
||||
* @return array|false
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected static function guessControllerAction($path_explode, $action, $suffix, $class_prefix)
|
||||
{
|
||||
$map[] = trim("$class_prefix\\app\\controller\\" . \implode('\\', $path_explode), '\\');
|
||||
foreach ($path_explode as $index => $section) {
|
||||
$tmp = $path_explode;
|
||||
\array_splice($tmp, $index, 1, [$section, 'controller']);
|
||||
$map[] = trim("$class_prefix\\" . \implode('\\', \array_merge(['app'], $tmp)), '\\');
|
||||
}
|
||||
foreach ($map as $item) {
|
||||
$map[] = $item . '\\index';
|
||||
}
|
||||
|
||||
foreach ($map as $controller_class) {
|
||||
$controller_class .= $suffix;
|
||||
if ($controller_action = static::getControllerAction($controller_class, $action)) {
|
||||
return $controller_action;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller_class
|
||||
* @param string $action
|
||||
* @return array|false
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected static function getControllerAction(string $controller_class, string $action)
|
||||
{
|
||||
// Disable calling magic methods
|
||||
if (\strpos($action, '__') === 0) {
|
||||
return false;
|
||||
}
|
||||
if (($controller_class = static::getController($controller_class)) && ($action = static::getAction($controller_class, $action))) {
|
||||
return [
|
||||
'plugin' => static::getPluginByClass($controller_class),
|
||||
'app' => static::getAppByController($controller_class),
|
||||
'controller' => $controller_class,
|
||||
'action' => $action
|
||||
];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller_class
|
||||
* @return string|false
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected static function getController(string $controller_class)
|
||||
{
|
||||
if (\class_exists($controller_class)) {
|
||||
return (new \ReflectionClass($controller_class))->name;
|
||||
}
|
||||
$explodes = \explode('\\', strtolower(ltrim($controller_class, '\\')));
|
||||
$base_path = $explodes[0] === 'plugin' ? BASE_PATH . '/plugin' : static::$_appPath;
|
||||
unset($explodes[0]);
|
||||
$file_name = \array_pop($explodes) . '.php';
|
||||
$found = true;
|
||||
foreach ($explodes as $path_section) {
|
||||
if (!$found) {
|
||||
break;
|
||||
}
|
||||
$dirs = Util::scanDir($base_path, false);
|
||||
$found = false;
|
||||
foreach ($dirs as $name) {
|
||||
$path = "$base_path/$name";
|
||||
if (\is_dir($path) && \strtolower($name) === $path_section) {
|
||||
$base_path = $path;
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
return false;
|
||||
}
|
||||
foreach (\scandir($base_path) ?: [] as $name) {
|
||||
if (\strtolower($name) === $file_name) {
|
||||
require_once "$base_path/$name";
|
||||
if (\class_exists($controller_class, false)) {
|
||||
return (new \ReflectionClass($controller_class))->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller_class
|
||||
* @param string $action
|
||||
* @return string|false
|
||||
*/
|
||||
protected static function getAction(string $controller_class, string $action)
|
||||
{
|
||||
$methods = \get_class_methods($controller_class);
|
||||
$action = \strtolower($action);
|
||||
$found = false;
|
||||
foreach ($methods as $candidate) {
|
||||
if (\strtolower($candidate) === $action) {
|
||||
$action = $candidate;
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
return $action;
|
||||
}
|
||||
|
||||
// Action is not public method
|
||||
if (\method_exists($controller_class, $action)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (\method_exists($controller_class, '__call')) {
|
||||
return $action;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller_class
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function getPluginByClass(string $controller_class)
|
||||
{
|
||||
$controller_class = \trim($controller_class, '\\');
|
||||
$tmp = \explode('\\', $controller_class, 3);
|
||||
if ($tmp[0] !== 'plugin') {
|
||||
return '';
|
||||
}
|
||||
return $tmp[1] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function getPluginByPath(string $path)
|
||||
{
|
||||
$path = \trim($path, '/');
|
||||
$tmp = \explode('/', $path, 3);
|
||||
if ($tmp[0] !== 'app') {
|
||||
return '';
|
||||
}
|
||||
return $tmp[1] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller_class
|
||||
* @return mixed|string
|
||||
*/
|
||||
protected static function getAppByController(string $controller_class)
|
||||
{
|
||||
$controller_class = \trim($controller_class, '\\');
|
||||
$tmp = \explode('\\', $controller_class, 5);
|
||||
$pos = $tmp[0] === 'plugin' ? 3 : 1;
|
||||
if (!isset($tmp[$pos])) {
|
||||
return '';
|
||||
}
|
||||
return \strtolower($tmp[$pos]) === 'controller' ? '' : $tmp[$pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @return false|string
|
||||
*/
|
||||
public static function execPhpFile(string $file)
|
||||
{
|
||||
\ob_start();
|
||||
// Try to include php file.
|
||||
try {
|
||||
include $file;
|
||||
} catch (\Exception $e) {
|
||||
echo $e;
|
||||
}
|
||||
return \ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @return string
|
||||
*/
|
||||
protected static function getRealMethod(string $class, string $method)
|
||||
{
|
||||
$method = \strtolower($method);
|
||||
$methods = \get_class_methods($class);
|
||||
foreach ($methods as $candidate) {
|
||||
if (\strtolower($candidate) === $method) {
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
return $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plugin
|
||||
* @param string $key
|
||||
* @param $default
|
||||
* @return array|mixed|null
|
||||
*/
|
||||
protected static function config(string $plugin, string $key, $default = null)
|
||||
{
|
||||
return Config::get($plugin ? "plugin.$plugin.$key" : $key, $default);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman;
|
||||
|
||||
use Workerman\Worker;
|
||||
|
||||
interface Bootstrap
|
||||
{
|
||||
/**
|
||||
* onWorkerStart
|
||||
*
|
||||
* @param Worker $worker
|
||||
* @return mixed
|
||||
*/
|
||||
public static function start($worker);
|
||||
}
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman;
|
||||
|
||||
class Config
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_config = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $_configPath = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $_loaded = false;
|
||||
|
||||
/**
|
||||
* @param string $config_path
|
||||
* @param array $exclude_file
|
||||
* @param string|null $key
|
||||
* @return void
|
||||
*/
|
||||
public static function load(string $config_path, array $exclude_file = [], string $key = null)
|
||||
{
|
||||
static::$_configPath = $config_path;
|
||||
if (!$config_path) {
|
||||
return;
|
||||
}
|
||||
static::$_loaded = false;
|
||||
$config = static::loadFromDir($config_path, $exclude_file);
|
||||
if (!$config) {
|
||||
static::$_loaded = true;
|
||||
return;
|
||||
}
|
||||
if ($key !== null) {
|
||||
foreach (\array_reverse(\explode('.', $key)) as $k) {
|
||||
$config = [$k => $config];
|
||||
}
|
||||
}
|
||||
static::$_config = \array_replace_recursive(static::$_config, $config);
|
||||
static::formatConfig();
|
||||
static::$_loaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This deprecated method will certainly be removed in the future
|
||||
*
|
||||
* @deprecated
|
||||
* @param string $config_path
|
||||
* @param array $exclude_file
|
||||
* @return void
|
||||
*/
|
||||
public static function reload(string $config_path, array $exclude_file = [])
|
||||
{
|
||||
static::load($config_path, $exclude_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function clear()
|
||||
{
|
||||
static::$_config = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected static function formatConfig()
|
||||
{
|
||||
$config = static::$_config;
|
||||
// Merge log config
|
||||
foreach ($config['plugin'] ?? [] as $firm => $projects) {
|
||||
if (isset($projects['app'])) {
|
||||
foreach ($projects['log'] ?? [] as $key => $item) {
|
||||
$config['log']["plugin.$firm.$key"] = $item;
|
||||
}
|
||||
}
|
||||
foreach ($projects as $name => $project) {
|
||||
if (!\is_array($project)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($project['log'] ?? [] as $key => $item) {
|
||||
$config['log']["plugin.$firm.$name.$key"] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Merge database config
|
||||
foreach ($config['plugin'] ?? [] as $firm => $projects) {
|
||||
if (isset($projects['app'])) {
|
||||
foreach ($projects['database']['connections'] ?? [] as $key => $connection) {
|
||||
$config['database']['connections']["plugin.$firm.$key"] = $connection;
|
||||
}
|
||||
}
|
||||
foreach ($projects as $name => $project) {
|
||||
if (!\is_array($project)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($project['database']['connections'] ?? [] as $key => $connection) {
|
||||
$config['database']['connections']["plugin.$firm.$name.$key"] = $connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($config['database']['connections'])) {
|
||||
$config['database']['default'] = $config['database']['default'] ?? key($config['database']['connections']);
|
||||
}
|
||||
// Merge thinkorm config
|
||||
foreach ($config['plugin'] ?? [] as $firm => $projects) {
|
||||
if (isset($projects['app'])) {
|
||||
foreach ($projects['thinkorm']['connections'] ?? [] as $key => $connection) {
|
||||
$config['thinkorm']['connections']["plugin.$firm.$key"] = $connection;
|
||||
}
|
||||
}
|
||||
foreach ($projects as $name => $project) {
|
||||
if (!\is_array($project)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($project['thinkorm']['connections'] ?? [] as $key => $connection) {
|
||||
$config['thinkorm']['connections']["plugin.$firm.$name.$key"] = $connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($config['thinkorm']['connections'])) {
|
||||
$config['thinkorm']['default'] = $config['thinkorm']['default'] ?? \key($config['thinkorm']['connections']);
|
||||
}
|
||||
// Merge redis config
|
||||
foreach ($config['plugin'] ?? [] as $firm => $projects) {
|
||||
if (isset($projects['app'])) {
|
||||
foreach ($projects['redis'] ?? [] as $key => $connection) {
|
||||
$config['redis']["plugin.$firm.$key"] = $connection;
|
||||
}
|
||||
}
|
||||
foreach ($projects as $name => $project) {
|
||||
if (!\is_array($project)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($project['redis'] ?? [] as $key => $connection) {
|
||||
$config['redis']["plugin.$firm.$name.$key"] = $connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
static::$_config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $config_path
|
||||
* @param array $exclude_file
|
||||
* @return array
|
||||
*/
|
||||
public static function loadFromDir(string $config_path, array $exclude_file = [])
|
||||
{
|
||||
$all_config = [];
|
||||
$dir_iterator = new \RecursiveDirectoryIterator($config_path, \FilesystemIterator::FOLLOW_SYMLINKS);
|
||||
$iterator = new \RecursiveIteratorIterator($dir_iterator);
|
||||
foreach ($iterator as $file) {
|
||||
/** var SplFileInfo $file */
|
||||
if (\is_dir($file) || $file->getExtension() != 'php' || \in_array($file->getBaseName('.php'), $exclude_file)) {
|
||||
continue;
|
||||
}
|
||||
$app_config_file = $file->getPath() . '/app.php';
|
||||
if (!\is_file($app_config_file)) {
|
||||
continue;
|
||||
}
|
||||
$relative_path = \str_replace($config_path . DIRECTORY_SEPARATOR, '', substr($file, 0, -4));
|
||||
$explode = \array_reverse(\explode(DIRECTORY_SEPARATOR, $relative_path));
|
||||
if (\count($explode) >= 2) {
|
||||
$app_config = include $app_config_file;
|
||||
if (empty($app_config['enable'])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$config = include $file;
|
||||
foreach ($explode as $section) {
|
||||
$tmp = [];
|
||||
$tmp[$section] = $config;
|
||||
$config = $tmp;
|
||||
}
|
||||
$all_config = \array_replace_recursive($all_config, $config);
|
||||
}
|
||||
return $all_config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $key
|
||||
* @param mixed $default
|
||||
* @return array|mixed|void|null
|
||||
*/
|
||||
public static function get(string $key = null, $default = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
return static::$_config;
|
||||
}
|
||||
$key_array = \explode('.', $key);
|
||||
$value = static::$_config;
|
||||
$found = true;
|
||||
foreach ($key_array as $index) {
|
||||
if (!isset($value[$index])) {
|
||||
if (static::$_loaded) {
|
||||
return $default;
|
||||
}
|
||||
$found = false;
|
||||
break;
|
||||
}
|
||||
$value = $value[$index];
|
||||
}
|
||||
if ($found) {
|
||||
return $value;
|
||||
}
|
||||
return static::read($key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return array|mixed|null
|
||||
*/
|
||||
protected static function read(string $key, $default = null)
|
||||
{
|
||||
$path = static::$_configPath;
|
||||
if ($path === '') {
|
||||
return $default;
|
||||
}
|
||||
$keys = $key_array = \explode('.', $key);
|
||||
foreach ($key_array as $index => $section) {
|
||||
unset($keys[$index]);
|
||||
if (\is_file($file = "$path/$section.php")) {
|
||||
$config = include $file;
|
||||
return static::find($keys, $config, $default);
|
||||
}
|
||||
if (!\is_dir($path = "$path/$section")) {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $key_array
|
||||
* @param mixed $stack
|
||||
* @param mixed $default
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected static function find(array $key_array, $stack, $default)
|
||||
{
|
||||
if (!\is_array($stack)) {
|
||||
return $default;
|
||||
}
|
||||
$value = $stack;
|
||||
foreach ($key_array as $index) {
|
||||
if (!isset($value[$index])) {
|
||||
return $default;
|
||||
}
|
||||
$value = $value[$index];
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Webman;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Webman\Exception\NotFoundException;
|
||||
|
||||
/**
|
||||
* Class Container
|
||||
* @package Webman
|
||||
*/
|
||||
class Container implements ContainerInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $_instances = [];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $_definitions = [];
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function get(string $name)
|
||||
{
|
||||
if (!isset($this->_instances[$name])) {
|
||||
if (isset($this->_definitions[$name])) {
|
||||
$this->_instances[$name] = call_user_func($this->_definitions[$name], $this);
|
||||
} else {
|
||||
if (!\class_exists($name)) {
|
||||
throw new NotFoundException("Class '$name' not found");
|
||||
}
|
||||
$this->_instances[$name] = new $name();
|
||||
}
|
||||
}
|
||||
return $this->_instances[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return \array_key_exists($name, $this->_instances)
|
||||
|| array_key_exists($name, $this->_definitions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $constructor
|
||||
* @return mixed
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function make(string $name, array $constructor = [])
|
||||
{
|
||||
if (!\class_exists($name)) {
|
||||
throw new NotFoundException("Class '$name' not found");
|
||||
}
|
||||
return new $name(... array_values($constructor));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $definitions
|
||||
* @return $this
|
||||
*/
|
||||
public function addDefinitions(array $definitions)
|
||||
{
|
||||
$this->_definitions = array_merge($this->_definitions, $definitions);
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Exception;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
|
||||
/**
|
||||
* Class Handler
|
||||
* @package support\exception
|
||||
*/
|
||||
class ExceptionHandler implements ExceptionHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $_logger = null;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $_debug = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $dontReport = [];
|
||||
|
||||
/**
|
||||
* ExceptionHandler constructor.
|
||||
* @param $logger
|
||||
* @param $debug
|
||||
*/
|
||||
public function __construct($logger, $debug)
|
||||
{
|
||||
$this->_logger = $logger;
|
||||
$this->_debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Throwable $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Throwable $exception)
|
||||
{
|
||||
if ($this->shouldntReport($exception)) {
|
||||
return;
|
||||
}
|
||||
$logs = '';
|
||||
if ($request = \request()) {
|
||||
$logs = $request->getRealIp() . ' ' . $request->method() . ' ' . \trim($request->fullUrl(), '/');
|
||||
}
|
||||
$this->_logger->error($logs . PHP_EOL . $exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Throwable $exception
|
||||
* @return Response
|
||||
*/
|
||||
public function render(Request $request, Throwable $exception): Response
|
||||
{
|
||||
$code = $exception->getCode();
|
||||
if ($request->expectsJson()) {
|
||||
$json = ['code' => $code ? $code : 500, 'msg' => $this->_debug ? $exception->getMessage() : 'Server internal error'];
|
||||
$this->_debug && $json['traces'] = (string)$exception;
|
||||
return new Response(200, ['Content-Type' => 'application/json'],
|
||||
\json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
$error = $this->_debug ? \nl2br((string)$exception) : 'Server internal error';
|
||||
return new Response(500, [], $error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Throwable $e
|
||||
* @return bool
|
||||
*/
|
||||
protected function shouldntReport(Throwable $e)
|
||||
{
|
||||
foreach ($this->dontReport as $type) {
|
||||
if ($e instanceof $type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Exception;
|
||||
|
||||
use Throwable;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
|
||||
interface ExceptionHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @param Throwable $e
|
||||
* @return mixed
|
||||
*/
|
||||
public function report(Throwable $e);
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Throwable $e
|
||||
* @return Response
|
||||
*/
|
||||
public function render(Request $request, Throwable $e): Response;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Class FileException
|
||||
* @package Webman\Exception
|
||||
*/
|
||||
class FileException extends RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Exception;
|
||||
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
/**
|
||||
* Class NotFoundException
|
||||
* @package Webman\Exception
|
||||
*/
|
||||
class NotFoundException extends \Exception implements NotFoundExceptionInterface
|
||||
{
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman;
|
||||
|
||||
use Webman\Exception\FileException;
|
||||
|
||||
class File extends \SplFileInfo
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $destination
|
||||
* @return File
|
||||
*/
|
||||
public function move(string $destination)
|
||||
{
|
||||
\set_error_handler(function ($type, $msg) use (&$error) {
|
||||
$error = $msg;
|
||||
});
|
||||
$path = \pathinfo($destination, PATHINFO_DIRNAME);
|
||||
if (!\is_dir($path) && !\mkdir($path, 0777, true)) {
|
||||
\restore_error_handler();
|
||||
throw new FileException(\sprintf('Unable to create the "%s" directory (%s)', $path, \strip_tags($error)));
|
||||
}
|
||||
if (!rename($this->getPathname(), $destination)) {
|
||||
\restore_error_handler();
|
||||
throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $destination, \strip_tags($error)));
|
||||
}
|
||||
\restore_error_handler();
|
||||
@\chmod($destination, 0666 & ~\umask());
|
||||
return new self($destination);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Webman;
|
||||
|
||||
/**
|
||||
* This deprecated class will certainly be removed in the future.
|
||||
* Please use Webman\Session\FileSessionHandler
|
||||
* @deprecated
|
||||
* @package Webman
|
||||
*/
|
||||
class FileSessionHandler extends Session\FileSessionHandler
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Http;
|
||||
|
||||
use Webman\App;
|
||||
use Webman\Route\Route;
|
||||
|
||||
/**
|
||||
* Class Request
|
||||
* @package Webman\Http
|
||||
*/
|
||||
class Request extends \Workerman\Protocols\Http\Request
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $plugin = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $app = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $controller = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $action = null;
|
||||
|
||||
/**
|
||||
* @var Route
|
||||
*/
|
||||
public $route = null;
|
||||
|
||||
/**
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return $this->post() + $this->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string|null $default
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function input($name, $default = null)
|
||||
{
|
||||
$post = $this->post();
|
||||
if (isset($post[$name])) {
|
||||
return $post[$name];
|
||||
}
|
||||
$get = $this->get();
|
||||
return isset($get[$name]) ? $get[$name] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $keys
|
||||
* @return array
|
||||
*/
|
||||
public function only(array $keys)
|
||||
{
|
||||
$all = $this->all();
|
||||
$result = [];
|
||||
foreach ($keys as $key) {
|
||||
if (isset($all[$key])) {
|
||||
$result[$key] = $all[$key];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $keys
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function except(array $keys)
|
||||
{
|
||||
$all = $this->all();
|
||||
foreach ($keys as $key) {
|
||||
unset($all[$key]);
|
||||
}
|
||||
return $all;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $name
|
||||
* @return null|UploadFile[]|UploadFile
|
||||
*/
|
||||
public function file($name = null)
|
||||
{
|
||||
$files = parent::file($name);
|
||||
if (null === $files) {
|
||||
return $name === null ? [] : null;
|
||||
}
|
||||
if ($name !== null) {
|
||||
// Multi files
|
||||
if (\is_array(\current($files))) {
|
||||
return $this->parseFiles($files);
|
||||
}
|
||||
return $this->parseFile($files);
|
||||
}
|
||||
$upload_files = [];
|
||||
foreach ($files as $name => $file) {
|
||||
// Multi files
|
||||
if (\is_array(\current($file))) {
|
||||
$upload_files[$name] = $this->parseFiles($file);
|
||||
} else {
|
||||
$upload_files[$name] = $this->parseFile($file);
|
||||
}
|
||||
}
|
||||
return $upload_files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $file
|
||||
* @return UploadFile
|
||||
*/
|
||||
protected function parseFile(array $file)
|
||||
{
|
||||
return new UploadFile($file['tmp_name'], $file['name'], $file['type'], $file['error']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return array
|
||||
*/
|
||||
protected function parseFiles(array $files)
|
||||
{
|
||||
$upload_files = [];
|
||||
foreach ($files as $key => $file) {
|
||||
if (\is_array(\current($file))) {
|
||||
$upload_files[$key] = $this->parseFiles($file);
|
||||
} else {
|
||||
$upload_files[$key] = $this->parseFile($file);
|
||||
}
|
||||
}
|
||||
return $upload_files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRemoteIp()
|
||||
{
|
||||
return App::connection()->getRemoteIp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getRemotePort()
|
||||
{
|
||||
return App::connection()->getRemotePort();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLocalIp()
|
||||
{
|
||||
return App::connection()->getLocalIp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLocalPort()
|
||||
{
|
||||
return App::connection()->getLocalPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $safe_mode
|
||||
* @return string
|
||||
*/
|
||||
public function getRealIp(bool $safe_mode = true)
|
||||
{
|
||||
$remote_ip = $this->getRemoteIp();
|
||||
if ($safe_mode && !static::isIntranetIp($remote_ip)) {
|
||||
return $remote_ip;
|
||||
}
|
||||
return $this->header('x-real-ip', $this->header('x-forwarded-for',
|
||||
$this->header('client-ip', $this->header('x-client-ip',
|
||||
$this->header('via', $remote_ip)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function url()
|
||||
{
|
||||
return '//' . $this->host() . $this->path();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function fullUrl()
|
||||
{
|
||||
return '//' . $this->host() . $this->uri();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isAjax()
|
||||
{
|
||||
return $this->header('X-Requested-With') === 'XMLHttpRequest';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isPjax()
|
||||
{
|
||||
return (bool)$this->header('X-PJAX');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function expectsJson()
|
||||
{
|
||||
return ($this->isAjax() && !$this->isPjax()) || $this->acceptJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function acceptJson()
|
||||
{
|
||||
return false !== \strpos($this->header('accept', ''), 'json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ip
|
||||
* @return bool
|
||||
*/
|
||||
public static function isIntranetIp(string $ip)
|
||||
{
|
||||
// Not validate ip .
|
||||
if (!\filter_var($ip, \FILTER_VALIDATE_IP)) {
|
||||
return false;
|
||||
}
|
||||
// Is intranet ip ? For IPv4, the result of false may not be accurate, so we need to check it manually later .
|
||||
if (!\filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE)) {
|
||||
return true;
|
||||
}
|
||||
// Manual check only for IPv4 .
|
||||
if (!\filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
|
||||
return false;
|
||||
}
|
||||
// Manual check .
|
||||
$reserved_ips = [
|
||||
1681915904 => 1686110207, // 100.64.0.0 - 100.127.255.255
|
||||
3221225472 => 3221225727, // 192.0.0.0 - 192.0.0.255
|
||||
3221225984 => 3221226239, // 192.0.2.0 - 192.0.2.255
|
||||
3227017984 => 3227018239, // 192.88.99.0 - 192.88.99.255
|
||||
3323068416 => 3323199487, // 198.18.0.0 - 198.19.255.255
|
||||
3325256704 => 3325256959, // 198.51.100.0 - 198.51.100.255
|
||||
3405803776 => 3405804031, // 203.0.113.0 - 203.0.113.255
|
||||
3758096384 => 4026531839, // 224.0.0.0 - 239.255.255.255
|
||||
];
|
||||
$ip_long = \ip2long($ip);
|
||||
foreach ($reserved_ips as $ip_start => $ip_end) {
|
||||
if (($ip_long >= $ip_start) && ($ip_long <= $ip_end)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Http;
|
||||
|
||||
use Webman\App;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class Response
|
||||
* @package Webman\Http
|
||||
*/
|
||||
class Response extends \Workerman\Protocols\Http\Response
|
||||
{
|
||||
/**
|
||||
* @var Throwable
|
||||
*/
|
||||
protected $_exception = null;
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @return $this
|
||||
*/
|
||||
public function file(string $file)
|
||||
{
|
||||
if ($this->notModifiedSince($file)) {
|
||||
return $this->withStatus(304);
|
||||
}
|
||||
return $this->withFile($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param string $download_name
|
||||
* @return $this
|
||||
*/
|
||||
public function download(string $file, string $download_name = '')
|
||||
{
|
||||
$this->withFile($file);
|
||||
if ($download_name) {
|
||||
$this->header('Content-Disposition', "attachment; filename=\"$download_name\"");
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @return bool
|
||||
*/
|
||||
protected function notModifiedSince(string $file)
|
||||
{
|
||||
$if_modified_since = App::request()->header('if-modified-since');
|
||||
if ($if_modified_since === null || !($mtime = \filemtime($file))) {
|
||||
return false;
|
||||
}
|
||||
return $if_modified_since === \gmdate('D, d M Y H:i:s', $mtime) . ' GMT';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Throwable $exception
|
||||
* @return Throwable
|
||||
*/
|
||||
public function exception($exception = null)
|
||||
{
|
||||
if ($exception) {
|
||||
$this->_exception = $exception;
|
||||
}
|
||||
return $this->_exception;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Http;
|
||||
|
||||
use Webman\File;
|
||||
|
||||
/**
|
||||
* Class UploadFile
|
||||
* @package Webman\Http
|
||||
*/
|
||||
class UploadFile extends File
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $_uploadName = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $_uploadMimeType = null;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $_uploadErrorCode = null;
|
||||
|
||||
/**
|
||||
* UploadFile constructor.
|
||||
*
|
||||
* @param string $file_name
|
||||
* @param string $upload_name
|
||||
* @param string $upload_mime_type
|
||||
* @param int $upload_error_code
|
||||
*/
|
||||
public function __construct(string $file_name, string $upload_name, string $upload_mime_type, int $upload_error_code)
|
||||
{
|
||||
$this->_uploadName = $upload_name;
|
||||
$this->_uploadMimeType = $upload_mime_type;
|
||||
$this->_uploadErrorCode = $upload_error_code;
|
||||
parent::__construct($file_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUploadName()
|
||||
{
|
||||
return $this->_uploadName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUploadMimeType()
|
||||
{
|
||||
return $this->_uploadMimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUploadExtension()
|
||||
{
|
||||
return \pathinfo($this->_uploadName, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getUploadErrorCode()
|
||||
{
|
||||
return $this->_uploadErrorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
return $this->_uploadErrorCode === UPLOAD_ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @return string
|
||||
*/
|
||||
public function getUploadMineType()
|
||||
{
|
||||
return $this->_uploadMimeType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Webman;
|
||||
|
||||
class Install
|
||||
{
|
||||
const WEBMAN_PLUGIN = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $pathRelation = [
|
||||
'start.php' => 'start.php',
|
||||
'windows.php' => 'windows.php',
|
||||
'support/bootstrap.php' => 'support/bootstrap.php',
|
||||
'support/helpers.php' => 'support/helpers.php',
|
||||
];
|
||||
|
||||
/**
|
||||
* Install
|
||||
* @return void
|
||||
*/
|
||||
public static function install()
|
||||
{
|
||||
static::installByRelation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* installByRelation
|
||||
* @return void
|
||||
*/
|
||||
public static function installByRelation()
|
||||
{
|
||||
foreach (static::$pathRelation as $source => $dest) {
|
||||
if ($pos = strrpos($dest, '/')) {
|
||||
$parent_dir = base_path() . '/' . substr($dest, 0, $pos);
|
||||
if (!is_dir($parent_dir)) {
|
||||
mkdir($parent_dir, 0777, true);
|
||||
}
|
||||
}
|
||||
$source_file = __DIR__ . "/$source";
|
||||
copy_dir($source_file, base_path() . "/$dest", true);
|
||||
echo "Create $dest\r\n";
|
||||
if (is_file($source_file)) {
|
||||
@unlink($source_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Webman;
|
||||
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
class Middleware
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_instances = [];
|
||||
|
||||
/**
|
||||
* @param array $all_middlewares
|
||||
* @param string $plugin
|
||||
* @return void
|
||||
*/
|
||||
public static function load($all_middlewares, string $plugin = '')
|
||||
{
|
||||
if (!\is_array($all_middlewares)) {
|
||||
return;
|
||||
}
|
||||
foreach ($all_middlewares as $app_name => $middlewares) {
|
||||
if (!\is_array($middlewares)) {
|
||||
throw new \RuntimeException('Bad middleware config');
|
||||
}
|
||||
foreach ($middlewares as $class_name) {
|
||||
if (\method_exists($class_name, 'process')) {
|
||||
static::$_instances[$plugin][$app_name][] = [$class_name, 'process'];
|
||||
} else {
|
||||
// @todo Log
|
||||
echo "middleware $class_name::process not exsits\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plugin
|
||||
* @param string $app_name
|
||||
* @param bool $with_global_middleware
|
||||
* @return array|mixed
|
||||
*/
|
||||
public static function getMiddleware(string $plugin, string $app_name, bool $with_global_middleware = true)
|
||||
{
|
||||
$global_middleware = $with_global_middleware && isset(static::$_instances[$plugin]['']) ? static::$_instances[$plugin][''] : [];
|
||||
if ($app_name === '') {
|
||||
return \array_reverse($global_middleware);
|
||||
}
|
||||
$app_middleware = static::$_instances[$plugin][$app_name] ?? [];
|
||||
return \array_reverse(\array_merge($global_middleware, $app_middleware));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @return void
|
||||
*/
|
||||
public static function container($_)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman;
|
||||
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
|
||||
interface MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* Process an incoming server request.
|
||||
*
|
||||
* Processes an incoming server request in order to produce a response.
|
||||
* If unable to produce the response itself, it may delegate to the provided
|
||||
* request handler to do so.
|
||||
*/
|
||||
public function process(Request $request, callable $handler): Response;
|
||||
}
|
||||
+419
@@ -0,0 +1,419 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman;
|
||||
|
||||
use FastRoute\Dispatcher\GroupCountBased;
|
||||
use FastRoute\RouteCollector;
|
||||
use Webman\Route\Route as RouteObject;
|
||||
use function FastRoute\simpleDispatcher;
|
||||
|
||||
/**
|
||||
* Class Route
|
||||
* @package Webman
|
||||
*/
|
||||
class Route
|
||||
{
|
||||
/**
|
||||
* @var Route
|
||||
*/
|
||||
protected static $_instance = null;
|
||||
|
||||
/**
|
||||
* @var GroupCountBased
|
||||
*/
|
||||
protected static $_dispatcher = null;
|
||||
|
||||
/**
|
||||
* @var RouteCollector
|
||||
*/
|
||||
protected static $_collector = null;
|
||||
|
||||
/**
|
||||
* @var null|callable
|
||||
*/
|
||||
protected static $_fallback = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_nameList = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $_groupPrefix = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $_disableDefaultRoute = [];
|
||||
|
||||
/**
|
||||
* @var RouteObject[]
|
||||
*/
|
||||
protected static $_allRoutes = [];
|
||||
|
||||
/**
|
||||
* @var RouteObject[]
|
||||
*/
|
||||
protected $_routes = [];
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function get(string $path, $callback)
|
||||
{
|
||||
return static::addRoute('GET', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function post(string $path, $callback)
|
||||
{
|
||||
return static::addRoute('POST', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function put(string $path, $callback)
|
||||
{
|
||||
return static::addRoute('PUT', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function patch(string $path, $callback)
|
||||
{
|
||||
return static::addRoute('PATCH', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function delete(string $path, $callback)
|
||||
{
|
||||
return static::addRoute('DELETE', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function head(string $path, $callback)
|
||||
{
|
||||
return static::addRoute('HEAD', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function options(string $path, $callback)
|
||||
{
|
||||
return static::addRoute('OPTIONS', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function any(string $path, $callback)
|
||||
{
|
||||
return static::addRoute(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'], $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $method
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function add($method, string $path, $callback)
|
||||
{
|
||||
return static::addRoute($method, $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|callable $path
|
||||
* @param callable|null $callback
|
||||
* @return static
|
||||
*/
|
||||
public static function group($path, callable $callback = null)
|
||||
{
|
||||
if ($callback === null) {
|
||||
$callback = $path;
|
||||
$path = '';
|
||||
}
|
||||
$previous_group_prefix = static::$_groupPrefix;
|
||||
static::$_groupPrefix = $previous_group_prefix . $path;
|
||||
$instance = static::$_instance = new static;
|
||||
static::$_collector->addGroup($path, $callback);
|
||||
static::$_instance = null;
|
||||
static::$_groupPrefix = $previous_group_prefix;
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $controller
|
||||
* @param array $options
|
||||
* @return void
|
||||
*/
|
||||
public static function resource(string $name, string $controller, array $options = [])
|
||||
{
|
||||
$name = trim($name, '/');
|
||||
if (\is_array($options) && !empty($options)) {
|
||||
$diff_options = \array_diff($options, ['index', 'create', 'store', 'update', 'show', 'edit', 'destroy', 'recovery']);
|
||||
if (!empty($diff_options)) {
|
||||
foreach ($diff_options as $action) {
|
||||
static::any("/{$name}/{$action}[/{id}]", [$controller, $action])->name("{$name}.{$action}");
|
||||
}
|
||||
}
|
||||
// 注册路由 由于顺序不同会导致路由无效 因此不适用循环注册
|
||||
if (\in_array('index', $options)) static::get("/{$name}", [$controller, 'index'])->name("{$name}.index");
|
||||
if (\in_array('create', $options)) static::get("/{$name}/create", [$controller, 'create'])->name("{$name}.create");
|
||||
if (\in_array('store', $options)) static::post("/{$name}", [$controller, 'store'])->name("{$name}.store");
|
||||
if (\in_array('update', $options)) static::put("/{$name}/{id}", [$controller, 'update'])->name("{$name}.update");
|
||||
if (\in_array('show', $options)) static::get("/{$name}/{id}", [$controller, 'show'])->name("{$name}.show");
|
||||
if (\in_array('edit', $options)) static::get("/{$name}/{id}/edit", [$controller, 'edit'])->name("{$name}.edit");
|
||||
if (\in_array('destroy', $options)) static::delete("/{$name}/{id}", [$controller, 'destroy'])->name("{$name}.destroy");
|
||||
if (\in_array('recovery', $options)) static::put("/{$name}/{id}/recovery", [$controller, 'recovery'])->name("{$name}.recovery");
|
||||
} else {
|
||||
//为空时自动注册所有常用路由
|
||||
if (\method_exists($controller, 'index')) static::get("/{$name}", [$controller, 'index'])->name("{$name}.index");
|
||||
if (\method_exists($controller, 'create')) static::get("/{$name}/create", [$controller, 'create'])->name("{$name}.create");
|
||||
if (\method_exists($controller, 'store')) static::post("/{$name}", [$controller, 'store'])->name("{$name}.store");
|
||||
if (\method_exists($controller, 'update')) static::put("/{$name}/{id}", [$controller, 'update'])->name("{$name}.update");
|
||||
if (\method_exists($controller, 'show')) static::get("/{$name}/{id}", [$controller, 'show'])->name("{$name}.show");
|
||||
if (\method_exists($controller, 'edit')) static::get("/{$name}/{id}/edit", [$controller, 'edit'])->name("{$name}.edit");
|
||||
if (\method_exists($controller, 'destroy')) static::delete("/{$name}/{id}", [$controller, 'destroy'])->name("{$name}.destroy");
|
||||
if (\method_exists($controller, 'recovery')) static::put("/{$name}/{id}/recovery", [$controller, 'recovery'])->name("{$name}.recovery");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RouteObject[]
|
||||
*/
|
||||
public static function getRoutes()
|
||||
{
|
||||
return static::$_allRoutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* disableDefaultRoute.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function disableDefaultRoute($plugin = '')
|
||||
{
|
||||
static::$_disableDefaultRoute[$plugin] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasDisableDefaultRoute($plugin = '')
|
||||
{
|
||||
return static::$_disableDefaultRoute[$plugin] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $middleware
|
||||
* @return $this
|
||||
*/
|
||||
public function middleware($middleware)
|
||||
{
|
||||
foreach ($this->_routes as $route) {
|
||||
$route->middleware($middleware);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RouteObject $route
|
||||
*/
|
||||
public function collect(RouteObject $route)
|
||||
{
|
||||
$this->_routes[] = $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param RouteObject $instance
|
||||
*/
|
||||
public static function setByName(string $name, RouteObject $instance)
|
||||
{
|
||||
static::$_nameList[$name] = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return null|RouteObject
|
||||
*/
|
||||
public static function getByName(string $name)
|
||||
{
|
||||
return static::$_nameList[$name] ?? null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param string $path
|
||||
* @return array
|
||||
*/
|
||||
public static function dispatch($method, string $path)
|
||||
{
|
||||
return static::$_dispatcher->dispatch($method, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return callable|false|string[]
|
||||
*/
|
||||
public static function convertToCallable(string $path, $callback)
|
||||
{
|
||||
if (\is_string($callback) && \strpos($callback, '@')) {
|
||||
$callback = \explode('@', $callback, 2);
|
||||
}
|
||||
|
||||
if (!\is_array($callback)) {
|
||||
if (!\is_callable($callback)) {
|
||||
$call_str = \is_scalar($callback) ? $callback : 'Closure';
|
||||
echo "Route $path $call_str is not callable\n";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$callback = \array_values($callback);
|
||||
if (!isset($callback[1]) || !\class_exists($callback[0]) || !\method_exists($callback[0], $callback[1])) {
|
||||
echo "Route $path " . \json_encode($callback) . " is not callable\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $methods
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
protected static function addRoute($methods, string $path, $callback)
|
||||
{
|
||||
$route = new RouteObject($methods, static::$_groupPrefix . $path, $callback);
|
||||
static::$_allRoutes[] = $route;
|
||||
|
||||
if ($callback = static::convertToCallable($path, $callback)) {
|
||||
static::$_collector->addRoute($methods, $path, ['callback' => $callback, 'route' => $route]);
|
||||
}
|
||||
if (static::$_instance) {
|
||||
static::$_instance->collect($route);
|
||||
}
|
||||
return $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $paths
|
||||
* @return void
|
||||
*/
|
||||
public static function load($paths)
|
||||
{
|
||||
if (!\is_array($paths)) {
|
||||
return;
|
||||
}
|
||||
static::$_dispatcher = simpleDispatcher(function (RouteCollector $route) use ($paths) {
|
||||
Route::setCollector($route);
|
||||
foreach ($paths as $config_path) {
|
||||
$route_config_file = $config_path . '/route.php';
|
||||
if (\is_file($route_config_file)) {
|
||||
require_once $route_config_file;
|
||||
}
|
||||
if (!is_dir($plugin_config_path = $config_path . '/plugin')) {
|
||||
continue;
|
||||
}
|
||||
$dir_iterator = new \RecursiveDirectoryIterator($plugin_config_path, \FilesystemIterator::FOLLOW_SYMLINKS);
|
||||
$iterator = new \RecursiveIteratorIterator($dir_iterator);
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->getBaseName('.php') !== 'route') {
|
||||
continue;
|
||||
}
|
||||
$app_config_file = pathinfo($file, PATHINFO_DIRNAME) . '/app.php';
|
||||
if (!is_file($app_config_file)) {
|
||||
continue;
|
||||
}
|
||||
$app_config = include $app_config_file;
|
||||
if (empty($app_config['enable'])) {
|
||||
continue;
|
||||
}
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RouteCollector $route
|
||||
* @return void
|
||||
*/
|
||||
public static function setCollector(RouteCollector $route)
|
||||
{
|
||||
static::$_collector = $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $callback
|
||||
* @param string $plugin
|
||||
* @return void
|
||||
*/
|
||||
public static function fallback(callable $callback, string $plugin = '')
|
||||
{
|
||||
static::$_fallback[$plugin] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable|null
|
||||
*/
|
||||
public static function getFallback(string $plugin = '')
|
||||
{
|
||||
return static::$_fallback[$plugin] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @return void
|
||||
*/
|
||||
public static function container()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Route;
|
||||
|
||||
use FastRoute\Dispatcher\GroupCountBased;
|
||||
use FastRoute\RouteCollector;
|
||||
use Webman\Route as Router;
|
||||
|
||||
/**
|
||||
* Class Route
|
||||
* @package Webman
|
||||
*/
|
||||
class Route
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $_name = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $_methods = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $_path = '';
|
||||
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $_callback = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $_middlewares = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $_params = [];
|
||||
|
||||
/**
|
||||
* Route constructor.
|
||||
*
|
||||
* @param array $methods
|
||||
* @param string $path
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function __construct($methods, string $path, $callback)
|
||||
{
|
||||
$this->_methods = (array)$methods;
|
||||
$this->_path = $path;
|
||||
$this->_callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->_name ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function name(string $name)
|
||||
{
|
||||
$this->_name = $name;
|
||||
Router::setByName($name, $this);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $middleware
|
||||
* @return $this|array
|
||||
*/
|
||||
public function middleware($middleware = null)
|
||||
{
|
||||
if ($middleware === null) {
|
||||
return $this->_middlewares;
|
||||
}
|
||||
$this->_middlewares = \array_merge($this->_middlewares, is_array($middleware) ? $middleware : [$middleware]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMethods()
|
||||
{
|
||||
return $this->_methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable
|
||||
*/
|
||||
public function getCallback()
|
||||
{
|
||||
return $this->_callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMiddleware()
|
||||
{
|
||||
return $this->_middlewares;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $name
|
||||
* @param $default
|
||||
* @return array|mixed|null
|
||||
*/
|
||||
public function param(string $name = null, $default = null)
|
||||
{
|
||||
if ($name === null) {
|
||||
return $this->_params;
|
||||
}
|
||||
return $this->_params[$name] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
* @return $this
|
||||
*/
|
||||
public function setParams(array $params)
|
||||
{
|
||||
$this->_params = \array_merge($this->_params, $params);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $parameters
|
||||
* @return string
|
||||
*/
|
||||
public function url($parameters = [])
|
||||
{
|
||||
if (empty($parameters)) {
|
||||
return $this->_path;
|
||||
}
|
||||
$path = \str_replace(['[', ']'], '', $this->_path);
|
||||
$path = \preg_replace_callback('/\{(.*?)(?:\:[^\}]*?)*?\}/', function ($matches) use (&$parameters) {
|
||||
if (!$parameters) {
|
||||
return $matches[0];
|
||||
}
|
||||
if (isset($parameters[$matches[1]])) {
|
||||
$value = $parameters[$matches[1]];
|
||||
unset($parameters[$matches[1]]);
|
||||
return $value;
|
||||
}
|
||||
$key = key($parameters);
|
||||
if (is_int($key)) {
|
||||
$value = $parameters[$key];
|
||||
unset($parameters[$key]);
|
||||
return $value;
|
||||
}
|
||||
return $matches[0];
|
||||
}, $path);
|
||||
return \count($parameters) > 0 ? $path . '?' . http_build_query($parameters) : $path;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Session;
|
||||
|
||||
use FastRoute\Dispatcher\GroupCountBased;
|
||||
use FastRoute\RouteCollector;
|
||||
use Workerman\Protocols\Http\Session\FileSessionHandler as FileHandler;
|
||||
|
||||
/**
|
||||
* Class FileSessionHandler
|
||||
* @package Webman
|
||||
*/
|
||||
class FileSessionHandler extends FileHandler
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Session;
|
||||
|
||||
use Workerman\Protocols\Http\Session\RedisClusterSessionHandler as RedisClusterHandler;
|
||||
|
||||
class RedisClusterSessionHandler extends RedisClusterHandler
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman\Session;
|
||||
|
||||
use FastRoute\Dispatcher\GroupCountBased;
|
||||
use FastRoute\RouteCollector;
|
||||
use Workerman\Protocols\Http\Session\RedisSessionHandler as RedisHandler;
|
||||
|
||||
/**
|
||||
* Class FileSessionHandler
|
||||
* @package Webman
|
||||
*/
|
||||
class RedisSessionHandler extends RedisHandler
|
||||
{
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman;
|
||||
|
||||
/**
|
||||
* Class Util
|
||||
* @package Webman
|
||||
*/
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* @param string $path
|
||||
* @return array
|
||||
*/
|
||||
public static function scanDir(string $base_path, $with_base_path = true): array
|
||||
{
|
||||
if (!is_dir($base_path)) {
|
||||
return [];
|
||||
}
|
||||
$paths = \array_diff(\scandir($base_path), array('.', '..')) ?: [];
|
||||
return $with_base_path ? \array_map(function($path) use ($base_path) {
|
||||
return $base_path . DIRECTORY_SEPARATOR . $path;
|
||||
}, $paths) : $paths;
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace Webman;
|
||||
|
||||
interface View
|
||||
{
|
||||
/**
|
||||
* @param $template
|
||||
* @param $vars
|
||||
* @param null $app
|
||||
* @return string
|
||||
*/
|
||||
static function render(string $template, array $vars, string $app = null);
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace support;
|
||||
|
||||
use Dotenv\Dotenv;
|
||||
use Webman\Config;
|
||||
use Webman\Util;
|
||||
use Workerman\Connection\TcpConnection;
|
||||
use Workerman\Protocols\Http;
|
||||
use Workerman\Worker;
|
||||
|
||||
class App
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function run()
|
||||
{
|
||||
ini_set('display_errors', 'on');
|
||||
error_reporting(E_ALL);
|
||||
|
||||
if (class_exists(Dotenv::class) && file_exists(run_path('.env'))) {
|
||||
if (method_exists(Dotenv::class, 'createUnsafeImmutable')) {
|
||||
Dotenv::createUnsafeImmutable(run_path())->load();
|
||||
} else {
|
||||
Dotenv::createMutable(run_path())->load();
|
||||
}
|
||||
}
|
||||
|
||||
static::loadAllConfig(['route', 'container']);
|
||||
|
||||
$error_reporting = config('app.error_reporting');
|
||||
if (isset($error_reporting)) {
|
||||
error_reporting($error_reporting);
|
||||
}
|
||||
if ($timezone = config('app.default_timezone')) {
|
||||
date_default_timezone_set($timezone);
|
||||
}
|
||||
|
||||
$runtime_logs_path = runtime_path() . DIRECTORY_SEPARATOR . 'logs';
|
||||
if (!file_exists($runtime_logs_path) || !is_dir($runtime_logs_path)) {
|
||||
if (!mkdir($runtime_logs_path, 0777, true)) {
|
||||
throw new \RuntimeException("Failed to create runtime logs directory. Please check the permission.");
|
||||
}
|
||||
}
|
||||
|
||||
$runtime_views_path = runtime_path() . DIRECTORY_SEPARATOR . 'views';
|
||||
if (!file_exists($runtime_views_path) || !is_dir($runtime_views_path)) {
|
||||
if (!mkdir($runtime_views_path, 0777, true)) {
|
||||
throw new \RuntimeException("Failed to create runtime views directory. Please check the permission.");
|
||||
}
|
||||
}
|
||||
|
||||
Worker::$onMasterReload = function () {
|
||||
if (function_exists('opcache_get_status')) {
|
||||
if ($status = \opcache_get_status()) {
|
||||
if (isset($status['scripts']) && $scripts = $status['scripts']) {
|
||||
foreach (array_keys($scripts) as $file) {
|
||||
\opcache_invalidate($file, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$config = config('server');
|
||||
Worker::$pidFile = $config['pid_file'];
|
||||
Worker::$stdoutFile = $config['stdout_file'];
|
||||
Worker::$logFile = $config['log_file'];
|
||||
Worker::$eventLoopClass = $config['event_loop'] ?? '';
|
||||
TcpConnection::$defaultMaxPackageSize = $config['max_package_size'] ?? 10 * 1024 * 1024;
|
||||
if (property_exists(Worker::class, 'statusFile')) {
|
||||
Worker::$statusFile = $config['status_file'] ?? '';
|
||||
}
|
||||
if (property_exists(Worker::class, 'stopTimeout')) {
|
||||
Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
|
||||
}
|
||||
|
||||
if ($config['listen']) {
|
||||
$worker = new Worker($config['listen'], $config['context']);
|
||||
$property_map = [
|
||||
'name',
|
||||
'count',
|
||||
'user',
|
||||
'group',
|
||||
'reusePort',
|
||||
'transport',
|
||||
'protocol'
|
||||
];
|
||||
foreach ($property_map as $property) {
|
||||
if (isset($config[$property])) {
|
||||
$worker->$property = $config[$property];
|
||||
}
|
||||
}
|
||||
|
||||
$worker->onWorkerStart = function ($worker) {
|
||||
require_once \base_path() . '/support/bootstrap.php';
|
||||
$app = new \Webman\App(config('app.request_class', Request::class), Log::channel('default'), app_path(), public_path());
|
||||
$worker->onMessage = [$app, 'onMessage'];
|
||||
\call_user_func([$app, 'onWorkerStart'], $worker);
|
||||
};
|
||||
}
|
||||
|
||||
// Windows does not support custom processes.
|
||||
if (\DIRECTORY_SEPARATOR === '/') {
|
||||
foreach (config('process', []) as $process_name => $config) {
|
||||
worker_start($process_name, $config);
|
||||
}
|
||||
foreach (config('plugin', []) as $firm => $projects) {
|
||||
foreach ($projects as $name => $project) {
|
||||
if (!is_array($project)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($project['process'] ?? [] as $process_name => $config) {
|
||||
worker_start("plugin.$firm.$name.$process_name", $config);
|
||||
}
|
||||
}
|
||||
foreach ($projects['process'] ?? [] as $process_name => $config) {
|
||||
worker_start("plugin.$firm.$process_name", $config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Worker::runAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $excludes
|
||||
* @return void
|
||||
*/
|
||||
public static function loadAllConfig(array $excludes = [])
|
||||
{
|
||||
Config::load(config_path(), $excludes);
|
||||
$directory = base_path() . '/plugin';
|
||||
foreach (Util::scanDir($directory, false) as $name) {
|
||||
$dir = "$directory/$name/config";
|
||||
if (\is_dir($dir)) {
|
||||
Config::load($dir, $excludes, "plugin.$name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace support;
|
||||
|
||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||
use Symfony\Component\Cache\Psr16Cache;
|
||||
|
||||
/**
|
||||
* Class Cache
|
||||
* @package support\bootstrap
|
||||
*
|
||||
* Strings methods
|
||||
* @method static mixed get($key, $default = null)
|
||||
* @method static bool set($key, $value, $ttl = null)
|
||||
* @method static bool delete($key)
|
||||
* @method static bool clear()
|
||||
* @method static iterable getMultiple($keys, $default = null)
|
||||
* @method static bool setMultiple($values, $ttl = null)
|
||||
* @method static bool deleteMultiple($keys)
|
||||
* @method static bool has($key)
|
||||
*/
|
||||
class Cache
|
||||
{
|
||||
/**
|
||||
* @var Psr16Cache
|
||||
*/
|
||||
public static $_instance = null;
|
||||
|
||||
/**
|
||||
* @return Psr16Cache
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
if (!static::$_instance) {
|
||||
$adapter = new RedisAdapter(Redis::connection()->client());
|
||||
self::$_instance = new Psr16Cache($adapter);
|
||||
}
|
||||
return static::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public static function __callStatic($name, $arguments)
|
||||
{
|
||||
return static::instance()->{$name}(... $arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Webman\Config;
|
||||
|
||||
/**
|
||||
* Class Container
|
||||
* @package support
|
||||
* @method static mixed get($name)
|
||||
* @method static mixed make($name, array $parameters)
|
||||
* @method static bool has($name)
|
||||
*/
|
||||
class Container
|
||||
{
|
||||
/**
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public static function instance(string $plugin = '')
|
||||
{
|
||||
return Config::get($plugin ? "plugin.$plugin.container" : 'container');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public static function __callStatic(string $name, array $arguments)
|
||||
{
|
||||
$plugin = \Webman\App::getPluginByClass($name);
|
||||
return static::instance($plugin)->{$name}(... $arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager;
|
||||
|
||||
/**
|
||||
* Class Db
|
||||
* @package support
|
||||
* @method static array select(string $query, $bindings = [], $useReadPdo = true)
|
||||
* @method static int insert(string $query, $bindings = [])
|
||||
* @method static int update(string $query, $bindings = [])
|
||||
* @method static int delete(string $query, $bindings = [])
|
||||
* @method static bool statement(string $query, $bindings = [])
|
||||
* @method static mixed transaction(\Closure $callback, $attempts = 1)
|
||||
* @method static void beginTransaction()
|
||||
* @method static void rollBack($toLevel = null)
|
||||
* @method static void commit()
|
||||
*/
|
||||
class Db extends Manager
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support;
|
||||
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
use Monolog\Handler\FormattableHandlerInterface;
|
||||
use Monolog\Handler\HandlerInterface;
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
* Class Log
|
||||
* @package support
|
||||
*
|
||||
* @method static void log($level, $message, array $context = [])
|
||||
* @method static void debug($message, array $context = [])
|
||||
* @method static void info($message, array $context = [])
|
||||
* @method static void notice($message, array $context = [])
|
||||
* @method static void warning($message, array $context = [])
|
||||
* @method static void error($message, array $context = [])
|
||||
* @method static void critical($message, array $context = [])
|
||||
* @method static void alert($message, array $context = [])
|
||||
* @method static void emergency($message, array $context = [])
|
||||
*/
|
||||
class Log
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_instance = [];
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return Logger
|
||||
*/
|
||||
public static function channel(string $name = 'default')
|
||||
{
|
||||
if (!isset(static::$_instance[$name])) {
|
||||
$config = \config('log', [])[$name];
|
||||
$handlers = self::handlers($config);
|
||||
$processors = self::processors($config);
|
||||
static::$_instance[$name] = new Logger($name, $handlers, $processors);
|
||||
}
|
||||
return static::$_instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @return array
|
||||
*/
|
||||
protected static function handlers(array $config): array
|
||||
{
|
||||
$handlerConfigs = $config['handlers'] ?? [[]];
|
||||
$handlers = [];
|
||||
foreach ($handlerConfigs as $value) {
|
||||
$class = $value['class'] ?? [];
|
||||
$constructor = $value['constructor'] ?? [];
|
||||
|
||||
$formatterConfig = $value['formatter'] ?? [];
|
||||
|
||||
$class && $handlers[] = self::handler($class, $constructor, $formatterConfig);
|
||||
}
|
||||
|
||||
return $handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param array $constructor
|
||||
* @param array $formatterConfig
|
||||
* @return HandlerInterface
|
||||
*/
|
||||
protected static function handler(string $class, array $constructor, array $formatterConfig): HandlerInterface
|
||||
{
|
||||
/** @var HandlerInterface $handler */
|
||||
$handler = new $class(... \array_values($constructor));
|
||||
|
||||
if ($handler instanceof FormattableHandlerInterface && $formatterConfig) {
|
||||
$formatterClass = $formatterConfig['class'];
|
||||
$formatterConstructor = $formatterConfig['constructor'];
|
||||
|
||||
/** @var FormatterInterface $formatter */
|
||||
$formatter = new $formatterClass(... \array_values($formatterConstructor));
|
||||
|
||||
$handler->setFormatter($formatter);
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @return array
|
||||
*/
|
||||
protected static function processors(array $config): array
|
||||
{
|
||||
$result = [];
|
||||
if (!isset($config['processors']) && isset($config['processor'])) {
|
||||
$config['processors'] = [$config['processor']];
|
||||
}
|
||||
|
||||
foreach ($config['processors'] ?? [] as $value) {
|
||||
if (\is_array($value) && isset($value['class'])) {
|
||||
$value = new $value['class'](... \array_values($value['constructor'] ?? []));;
|
||||
}
|
||||
$result[] = $value;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public static function __callStatic(string $name, array $arguments)
|
||||
{
|
||||
return static::channel('default')->{$name}(... $arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model as BaseModel;
|
||||
|
||||
/**
|
||||
* @method static \Illuminate\Database\Eloquent\Model make($attributes = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withGlobalScope($identifier, $scope)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withoutGlobalScope($scope)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withoutGlobalScopes($scopes = null)
|
||||
* @method static array removedScopes()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder whereKey($id)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder whereKeyNot($id)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder where($column, $operator = null, $value = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Eloquent\Model|null firstWhere($column, $operator = null, $value = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Eloquent\Builder orWhere($column, $operator = null, $value = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder latest($column = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder oldest($column = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Collection hydrate($items)
|
||||
* @method static \Illuminate\Database\Eloquent\Collection fromQuery($query, $bindings = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|static[]|static|null find($id, $columns = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Collection findMany($ids, $columns = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|static|static[] findOrFail($id, $columns = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model|static findOrNew($id, $columns = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model|static firstOrNew($attributes = [], $values = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model|static firstOrCreate($attributes = [], $values = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model|static updateOrCreate($attributes, $values = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model|static firstOrFail($columns = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model|static|mixed firstOr($columns = [], $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Model sole($columns = [])
|
||||
* @method static mixed value($column)
|
||||
* @method static \Illuminate\Database\Eloquent\Collection[]|static[] get($columns = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model[]|static[] getModels($columns = [])
|
||||
* @method static array eagerLoadRelations($models)
|
||||
* @method static \Illuminate\Support\LazyCollection cursor()
|
||||
* @method static \Illuminate\Support\Collection pluck($column, $key = null)
|
||||
* @method static \Illuminate\Contracts\Pagination\LengthAwarePaginator paginate($perPage = null, $columns = [], $pageName = 'page', $page = null)
|
||||
* @method static \Illuminate\Contracts\Pagination\Paginator simplePaginate($perPage = null, $columns = [], $pageName = 'page', $page = null)
|
||||
* @method static \Illuminate\Contracts\Pagination\CursorPaginator cursorPaginate($perPage = null, $columns = [], $cursorName = 'cursor', $cursor = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Model|$this create($attributes = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model|$this forceCreate($attributes)
|
||||
* @method static int upsert($values, $uniqueBy, $update = null)
|
||||
* @method static void onDelete($callback)
|
||||
* @method static static|mixed scopes($scopes)
|
||||
* @method static static applyScopes()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder without($relations)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withOnly($relations)
|
||||
* @method static \Illuminate\Database\Eloquent\Model newModelInstance($attributes = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withCasts($casts)
|
||||
* @method static \Illuminate\Database\Query\Builder getQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder setQuery($query)
|
||||
* @method static \Illuminate\Database\Query\Builder toBase()
|
||||
* @method static array getEagerLoads()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder setEagerLoads($eagerLoad)
|
||||
* @method static \Illuminate\Database\Eloquent\Model getModel()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder setModel($model)
|
||||
* @method static \Closure getMacro($name)
|
||||
* @method static bool hasMacro($name)
|
||||
* @method static \Closure getGlobalMacro($name)
|
||||
* @method static bool hasGlobalMacro($name)
|
||||
* @method static static clone()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder orHas($relation, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder doesntHave($relation, $boolean = 'and', $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder orDoesntHave($relation)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder whereHas($relation, $callback = null, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder orWhereHas($relation, $callback = null, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder whereDoesntHave($relation, $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder orWhereDoesntHave($relation, $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder hasMorph($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder orHasMorph($relation, $types, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder doesntHaveMorph($relation, $types, $boolean = 'and', $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder orDoesntHaveMorph($relation, $types)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder whereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder orWhereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder whereDoesntHaveMorph($relation, $types, $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder orWhereDoesntHaveMorph($relation, $types, $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withAggregate($relations, $column, $function = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withCount($relations)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withMax($relation, $column)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withMin($relation, $column)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withSum($relation, $column)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withAvg($relation, $column)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder withExists($relation)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder mergeConstraintsFrom($from)
|
||||
* @method static \Illuminate\Support\Collection explain()
|
||||
* @method static bool chunk($count, $callback)
|
||||
* @method static \Illuminate\Support\Collection chunkMap($callback, $count = 1000)
|
||||
* @method static bool each($callback, $count = 1000)
|
||||
* @method static bool chunkById($count, $callback, $column = null, $alias = null)
|
||||
* @method static bool eachById($callback, $count = 1000, $column = null, $alias = null)
|
||||
* @method static \Illuminate\Support\LazyCollection lazy($chunkSize = 1000)
|
||||
* @method static \Illuminate\Support\LazyCollection lazyById($chunkSize = 1000, $column = null, $alias = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Model|object|static|null first($columns = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Model|object|null baseSole($columns = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Builder tap($callback)
|
||||
* @method static mixed when($value, $callback, $default = null)
|
||||
* @method static mixed unless($value, $callback, $default = null)
|
||||
* @method static \Illuminate\Database\Query\Builder select($columns = [])
|
||||
* @method static \Illuminate\Database\Query\Builder selectSub($query, $as)
|
||||
* @method static \Illuminate\Database\Query\Builder selectRaw($expression, $bindings = [])
|
||||
* @method static \Illuminate\Database\Query\Builder fromSub($query, $as)
|
||||
* @method static \Illuminate\Database\Query\Builder fromRaw($expression, $bindings = [])
|
||||
* @method static \Illuminate\Database\Query\Builder addSelect($column)
|
||||
* @method static \Illuminate\Database\Query\Builder distinct()
|
||||
* @method static \Illuminate\Database\Query\Builder from($table, $as = null)
|
||||
* @method static \Illuminate\Database\Query\Builder join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false)
|
||||
* @method static \Illuminate\Database\Query\Builder joinWhere($table, $first, $operator, $second, $type = 'inner')
|
||||
* @method static \Illuminate\Database\Query\Builder joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false)
|
||||
* @method static \Illuminate\Database\Query\Builder leftJoin($table, $first, $operator = null, $second = null)
|
||||
* @method static \Illuminate\Database\Query\Builder leftJoinWhere($table, $first, $operator, $second)
|
||||
* @method static \Illuminate\Database\Query\Builder leftJoinSub($query, $as, $first, $operator = null, $second = null)
|
||||
* @method static \Illuminate\Database\Query\Builder rightJoin($table, $first, $operator = null, $second = null)
|
||||
* @method static \Illuminate\Database\Query\Builder rightJoinWhere($table, $first, $operator, $second)
|
||||
* @method static \Illuminate\Database\Query\Builder rightJoinSub($query, $as, $first, $operator = null, $second = null)
|
||||
* @method static \Illuminate\Database\Query\Builder crossJoin($table, $first = null, $operator = null, $second = null)
|
||||
* @method static \Illuminate\Database\Query\Builder crossJoinSub($query, $as)
|
||||
* @method static void mergeWheres($wheres, $bindings)
|
||||
* @method static array prepareValueAndOperator($value, $operator, $useDefault = false)
|
||||
* @method static \Illuminate\Database\Query\Builder whereColumn($first, $operator = null, $second = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereColumn($first, $operator = null, $second = null)
|
||||
* @method static \Illuminate\Database\Query\Builder whereRaw($sql, $bindings = [], $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereRaw($sql, $bindings = [])
|
||||
* @method static \Illuminate\Database\Query\Builder whereIn($column, $values, $boolean = 'and', $not = false)
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereIn($column, $values)
|
||||
* @method static \Illuminate\Database\Query\Builder whereNotIn($column, $values, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereNotIn($column, $values)
|
||||
* @method static \Illuminate\Database\Query\Builder whereIntegerInRaw($column, $values, $boolean = 'and', $not = false)
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereIntegerInRaw($column, $values)
|
||||
* @method static \Illuminate\Database\Query\Builder whereIntegerNotInRaw($column, $values, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereIntegerNotInRaw($column, $values)
|
||||
* @method static \Illuminate\Database\Query\Builder whereNull($columns, $boolean = 'and', $not = false)
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereNull($column)
|
||||
* @method static \Illuminate\Database\Query\Builder whereNotNull($columns, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder whereBetween($column, $values, $boolean = 'and', $not = false)
|
||||
* @method static \Illuminate\Database\Query\Builder whereBetweenColumns($column, $values, $boolean = 'and', $not = false)
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereBetween($column, $values)
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereBetweenColumns($column, $values)
|
||||
* @method static \Illuminate\Database\Query\Builder whereNotBetween($column, $values, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder whereNotBetweenColumns($column, $values, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereNotBetween($column, $values)
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereNotBetweenColumns($column, $values)
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereNotNull($column)
|
||||
* @method static \Illuminate\Database\Query\Builder whereDate($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereDate($column, $operator, $value = null)
|
||||
* @method static \Illuminate\Database\Query\Builder whereTime($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereTime($column, $operator, $value = null)
|
||||
* @method static \Illuminate\Database\Query\Builder whereDay($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereDay($column, $operator, $value = null)
|
||||
* @method static \Illuminate\Database\Query\Builder whereMonth($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereMonth($column, $operator, $value = null)
|
||||
* @method static \Illuminate\Database\Query\Builder whereYear($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereYear($column, $operator, $value = null)
|
||||
* @method static \Illuminate\Database\Query\Builder whereNested($callback, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder forNestedWhere()
|
||||
* @method static \Illuminate\Database\Query\Builder addNestedWhereQuery($query, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder whereExists($callback, $boolean = 'and', $not = false)
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereExists($callback, $not = false)
|
||||
* @method static \Illuminate\Database\Query\Builder whereNotExists($callback, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereNotExists($callback)
|
||||
* @method static \Illuminate\Database\Query\Builder addWhereExistsQuery($query, $boolean = 'and', $not = false)
|
||||
* @method static \Illuminate\Database\Query\Builder whereRowValues($columns, $operator, $values, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereRowValues($columns, $operator, $values)
|
||||
* @method static \Illuminate\Database\Query\Builder whereJsonContains($column, $value, $boolean = 'and', $not = false)
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereJsonContains($column, $value)
|
||||
* @method static \Illuminate\Database\Query\Builder whereJsonDoesntContain($column, $value, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereJsonDoesntContain($column, $value)
|
||||
* @method static \Illuminate\Database\Query\Builder whereJsonLength($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orWhereJsonLength($column, $operator, $value = null)
|
||||
* @method static \Illuminate\Database\Query\Builder dynamicWhere($method, $parameters)
|
||||
* @method static \Illuminate\Database\Query\Builder groupBy(...$groups)
|
||||
* @method static \Illuminate\Database\Query\Builder groupByRaw($sql, $bindings = [])
|
||||
* @method static \Illuminate\Database\Query\Builder having($column, $operator = null, $value = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orHaving($column, $operator = null, $value = null)
|
||||
* @method static \Illuminate\Database\Query\Builder havingBetween($column, $values, $boolean = 'and', $not = false)
|
||||
* @method static \Illuminate\Database\Query\Builder havingRaw($sql, $bindings = [], $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Query\Builder orHavingRaw($sql, $bindings = [])
|
||||
* @method static \Illuminate\Database\Query\Builder orderBy($column, $direction = 'asc')
|
||||
* @method static \Illuminate\Database\Query\Builder orderByDesc($column)
|
||||
* @method static \Illuminate\Database\Query\Builder inRandomOrder($seed = '')
|
||||
* @method static \Illuminate\Database\Query\Builder orderByRaw($sql, $bindings = [])
|
||||
* @method static \Illuminate\Database\Query\Builder skip($value)
|
||||
* @method static \Illuminate\Database\Query\Builder offset($value)
|
||||
* @method static \Illuminate\Database\Query\Builder take($value)
|
||||
* @method static \Illuminate\Database\Query\Builder limit($value)
|
||||
* @method static \Illuminate\Database\Query\Builder forPage($page, $perPage = 15)
|
||||
* @method static \Illuminate\Database\Query\Builder forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id')
|
||||
* @method static \Illuminate\Database\Query\Builder forPageAfterId($perPage = 15, $lastId = 0, $column = 'id')
|
||||
* @method static \Illuminate\Database\Query\Builder reorder($column = null, $direction = 'asc')
|
||||
* @method static \Illuminate\Database\Query\Builder union($query, $all = false)
|
||||
* @method static \Illuminate\Database\Query\Builder unionAll($query)
|
||||
* @method static \Illuminate\Database\Query\Builder lock($value = true)
|
||||
* @method static \Illuminate\Database\Query\Builder lockForUpdate()
|
||||
* @method static \Illuminate\Database\Query\Builder sharedLock()
|
||||
* @method static \Illuminate\Database\Query\Builder beforeQuery($callback)
|
||||
* @method static void applyBeforeQueryCallbacks()
|
||||
* @method static string toSql()
|
||||
* @method static int getCountForPagination($columns = [])
|
||||
* @method static string implode($column, $glue = '')
|
||||
* @method static bool exists()
|
||||
* @method static bool doesntExist()
|
||||
* @method static mixed existsOr($callback)
|
||||
* @method static mixed doesntExistOr($callback)
|
||||
* @method static int count($columns = '*')
|
||||
* @method static mixed min($column)
|
||||
* @method static mixed max($column)
|
||||
* @method static mixed sum($column)
|
||||
* @method static mixed avg($column)
|
||||
* @method static mixed average($column)
|
||||
* @method static mixed aggregate($function, $columns = [])
|
||||
* @method static float|int numericAggregate($function, $columns = [])
|
||||
* @method static bool insert($values)
|
||||
* @method static int insertOrIgnore($values)
|
||||
* @method static int insertGetId($values, $sequence = null)
|
||||
* @method static int insertUsing($columns, $query)
|
||||
* @method static bool updateOrInsert($attributes, $values = [])
|
||||
* @method static void truncate()
|
||||
* @method static \Illuminate\Database\Query\Expression raw($value)
|
||||
* @method static array getBindings()
|
||||
* @method static array getRawBindings()
|
||||
* @method static \Illuminate\Database\Query\Builder setBindings($bindings, $type = 'where')
|
||||
* @method static \Illuminate\Database\Query\Builder addBinding($value, $type = 'where')
|
||||
* @method static \Illuminate\Database\Query\Builder mergeBindings($query)
|
||||
* @method static array cleanBindings($bindings)
|
||||
* @method static \Illuminate\Database\Query\Processors\Processor getProcessor()
|
||||
* @method static \Illuminate\Database\Query\Grammars\Grammar getGrammar()
|
||||
* @method static \Illuminate\Database\Query\Builder useWritePdo()
|
||||
* @method static static cloneWithout($properties)
|
||||
* @method static static cloneWithoutBindings($except)
|
||||
* @method static \Illuminate\Database\Query\Builder dump()
|
||||
* @method static void dd()
|
||||
* @method static void macro($name, $macro)
|
||||
* @method static void mixin($mixin, $replace = true)
|
||||
* @method static mixed macroCall($method, $parameters)
|
||||
*/
|
||||
class Model extends BaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace support;
|
||||
|
||||
class Plugin
|
||||
{
|
||||
/**
|
||||
* @param $event
|
||||
* @return void
|
||||
*/
|
||||
public static function install($event)
|
||||
{
|
||||
static::findHepler();
|
||||
$operation = $event->getOperation();
|
||||
$autoload = \method_exists($operation, 'getPackage') ? $operation->getPackage()->getAutoload() : $operation->getTargetPackage()->getAutoload();
|
||||
if (!isset($autoload['psr-4'])) {
|
||||
return;
|
||||
}
|
||||
foreach ($autoload['psr-4'] as $namespace => $path) {
|
||||
$install_function = "\\{$namespace}Install::install";
|
||||
$plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN";
|
||||
if (\defined($plugin_const) && \is_callable($install_function)) {
|
||||
$install_function();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $event
|
||||
* @return void
|
||||
*/
|
||||
public static function update($event)
|
||||
{
|
||||
static::install($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $event
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall($event)
|
||||
{
|
||||
static::findHepler();
|
||||
$autoload = $event->getOperation()->getPackage()->getAutoload();
|
||||
if (!isset($autoload['psr-4'])) {
|
||||
return;
|
||||
}
|
||||
foreach ($autoload['psr-4'] as $namespace => $path) {
|
||||
$uninstall_function = "\\{$namespace}Install::uninstall";
|
||||
$plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN";
|
||||
if (defined($plugin_const) && is_callable($uninstall_function)) {
|
||||
$uninstall_function();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected static function findHepler()
|
||||
{
|
||||
// Plugin.php in vendor
|
||||
$file = __DIR__ . '/../../../../../support/helpers.php';
|
||||
if (\is_file($file)) {
|
||||
require_once $file;
|
||||
return;
|
||||
}
|
||||
// Plugin.php in webman
|
||||
require_once __DIR__ . '/helpers.php';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support;
|
||||
|
||||
use Illuminate\Events\Dispatcher;
|
||||
use Illuminate\Redis\Events\CommandExecuted;
|
||||
use Illuminate\Redis\RedisManager;
|
||||
use Workerman\Timer;
|
||||
use Workerman\Worker;
|
||||
|
||||
|
||||
/**
|
||||
* Class Redis
|
||||
* @package support
|
||||
*
|
||||
* Strings methods
|
||||
* @method static int append($key, $value)
|
||||
* @method static int bitCount($key)
|
||||
* @method static int decr($key, $value = 1)
|
||||
* @method static int decrBy($key, $value)
|
||||
* @method static string|bool get($key)
|
||||
* @method static int getBit($key, $offset)
|
||||
* @method static string getRange($key, $start, $end)
|
||||
* @method static string getSet($key, $value)
|
||||
* @method static int incr($key, $value = 1)
|
||||
* @method static int incrBy($key, $value)
|
||||
* @method static float incrByFloat($key, $value)
|
||||
* @method static array mGet(array $keys)
|
||||
* @method static array getMultiple(array $keys)
|
||||
* @method static bool mSet($pairs)
|
||||
* @method static bool mSetNx($pairs)
|
||||
* @method static bool set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
|
||||
* @method static bool setBit($key, $offset, $value)
|
||||
* @method static bool setEx($key, $ttl, $value)
|
||||
* @method static bool pSetEx($key, $ttl, $value)
|
||||
* @method static bool setNx($key, $value)
|
||||
* @method static string setRange($key, $offset, $value)
|
||||
* @method static int strLen($key)
|
||||
* Keys methods
|
||||
* @method static int del(...$keys)
|
||||
* @method static int unlink(...$keys)
|
||||
* @method static false|string dump($key)
|
||||
* @method static int exists(...$keys)
|
||||
* @method static bool expire($key, $ttl)
|
||||
* @method static bool pexpire($key, $ttl)
|
||||
* @method static bool expireAt($key, $timestamp)
|
||||
* @method static bool pexpireAt($key, $timestamp)
|
||||
* @method static array keys($pattern)
|
||||
* @method static bool|array scan($it)
|
||||
* @method static void migrate($host, $port, $keys, $dbIndex, $timeout, $copy = false, $replace = false)
|
||||
* @method static bool select($dbIndex)
|
||||
* @method static bool move($key, $dbIndex)
|
||||
* @method static string|int|bool object($information, $key)
|
||||
* @method static bool persist($key)
|
||||
* @method static string randomKey()
|
||||
* @method static bool rename($srcKey, $dstKey)
|
||||
* @method static bool renameNx($srcKey, $dstKey)
|
||||
* @method static string type($key)
|
||||
* @method static int|array sort($key, $options = [])
|
||||
* @method static int ttl($key)
|
||||
* @method static int pttl($key)
|
||||
* @method static void restore($key, $ttl, $value)
|
||||
* Hashes methods
|
||||
* @method static false|int hSet($key, $hashKey, $value)
|
||||
* @method static bool hSetNx($key, $hashKey, $value)
|
||||
* @method static false|string hGet($key, $hashKey)
|
||||
* @method static false|int hLen($key)
|
||||
* @method static false|int hDel($key, ...$hashKeys)
|
||||
* @method static array hKeys($key)
|
||||
* @method static array hVals($key)
|
||||
* @method static array hGetAll($key)
|
||||
* @method static bool hExists($key, $hashKey)
|
||||
* @method static int hIncrBy($key, $hashKey, $value)
|
||||
* @method static float hIncrByFloat($key, $hashKey, $value)
|
||||
* @method static bool hMSet($key, $members)
|
||||
* @method static array hMGet($key, $memberKeys)
|
||||
* @method static array hScan($key, $iterator, $pattern = '', $count = 0)
|
||||
* @method static int hStrLen($key, $hashKey)
|
||||
* Lists methods
|
||||
* @method static array blPop($keys, $timeout)
|
||||
* @method static array brPop($keys, $timeout)
|
||||
* @method static false|string bRPopLPush($srcKey, $dstKey, $timeout)
|
||||
* @method static false|string lIndex($key, $index)
|
||||
* @method static int lInsert($key, $position, $pivot, $value)
|
||||
* @method static false|string lPop($key)
|
||||
* @method static false|int lPush($key, ...$entries)
|
||||
* @method static false|int lPushx($key, $value)
|
||||
* @method static array lRange($key, $start, $end)
|
||||
* @method static false|int lRem($key, $count, $value)
|
||||
* @method static bool lSet($key, $index, $value)
|
||||
* @method static false|array lTrim($key, $start, $end)
|
||||
* @method static false|string rPop($key)
|
||||
* @method static false|string rPopLPush($srcKey, $dstKey)
|
||||
* @method static false|int rPush($key, ...$entries)
|
||||
* @method static false|int rPushX($key, $value)
|
||||
* @method static false|int lLen($key)
|
||||
* Sets methods
|
||||
* @method static int sAdd($key, $value)
|
||||
* @method static int sCard($key)
|
||||
* @method static array sDiff($keys)
|
||||
* @method static false|int sDiffStore($dst, $keys)
|
||||
* @method static false|array sInter($keys)
|
||||
* @method static false|int sInterStore($dst, $keys)
|
||||
* @method static bool sIsMember($key, $member)
|
||||
* @method static array sMembers($key)
|
||||
* @method static bool sMove($src, $dst, $member)
|
||||
* @method static false|string|array sPop($key, $count = 0)
|
||||
* @method static false|string|array sRandMember($key, $count = 0)
|
||||
* @method static int sRem($key, ...$members)
|
||||
* @method static array sUnion(...$keys)
|
||||
* @method static false|int sUnionStore($dst, ...$keys)
|
||||
* @method static false|array sScan($key, $iterator, $pattern = '', $count = 0)
|
||||
* Sorted sets methods
|
||||
* @method static array bzPopMin($keys, $timeout)
|
||||
* @method static array bzPopMax($keys, $timeout)
|
||||
* @method static int zAdd($key, $score, $value)
|
||||
* @method static int zCard($key)
|
||||
* @method static int zCount($key, $start, $end)
|
||||
* @method static double zIncrBy($key, $value, $member)
|
||||
* @method static int zinterstore($keyOutput, $arrayZSetKeys, $arrayWeights = [], $aggregateFunction = '')
|
||||
* @method static array zPopMin($key, $count)
|
||||
* @method static array zPopMax($key, $count)
|
||||
* @method static array zRange($key, $start, $end, $withScores = false)
|
||||
* @method static array zRangeByScore($key, $start, $end, $options = [])
|
||||
* @method static array zRevRangeByScore($key, $start, $end, $options = [])
|
||||
* @method static array zRangeByLex($key, $min, $max, $offset = 0, $limit = 0)
|
||||
* @method static int zRank($key, $member)
|
||||
* @method static int zRevRank($key, $member)
|
||||
* @method static int zRem($key, ...$members)
|
||||
* @method static int zRemRangeByRank($key, $start, $end)
|
||||
* @method static int zRemRangeByScore($key, $start, $end)
|
||||
* @method static array zRevRange($key, $start, $end, $withScores = false)
|
||||
* @method static double zScore($key, $member)
|
||||
* @method static int zunionstore($keyOutput, $arrayZSetKeys, $arrayWeights = [], $aggregateFunction = '')
|
||||
* @method static false|array zScan($key, $iterator, $pattern = '', $count = 0)
|
||||
* HyperLogLogs methods
|
||||
* @method static int pfAdd($key, $values)
|
||||
* @method static int pfCount($keys)
|
||||
* @method static bool pfMerge($dstKey, $srcKeys)
|
||||
* Geocoding methods
|
||||
* @method static int geoAdd($key, $longitude, $latitude, $member, ...$items)
|
||||
* @method static array geoHash($key, ...$members)
|
||||
* @method static array geoPos($key, ...$members)
|
||||
* @method static double geoDist($key, $members, $unit = '')
|
||||
* @method static int|array geoRadius($key, $longitude, $latitude, $radius, $unit, $options = [])
|
||||
* @method static array geoRadiusByMember($key, $member, $radius, $units, $options = [])
|
||||
* Streams methods
|
||||
* @method static int xAck($stream, $group, $arrMessages)
|
||||
* @method static string xAdd($strKey, $strId, $arrMessage, $iMaxLen = 0, $booApproximate = false)
|
||||
* @method static array xClaim($strKey, $strGroup, $strConsumer, $minIdleTime, $arrIds, $arrOptions = [])
|
||||
* @method static int xDel($strKey, $arrIds)
|
||||
* @method static mixed xGroup($command, $strKey, $strGroup, $strMsgId, $booMKStream = null)
|
||||
* @method static mixed xInfo($command, $strStream, $strGroup = null)
|
||||
* @method static int xLen($stream)
|
||||
* @method static array xPending($strStream, $strGroup, $strStart = 0, $strEnd = 0, $iCount = 0, $strConsumer = null)
|
||||
* @method static array xRange($strStream, $strStart, $strEnd, $iCount = 0)
|
||||
* @method static array xRead($arrStreams, $iCount = 0, $iBlock = null)
|
||||
* @method static array xReadGroup($strGroup, $strConsumer, $arrStreams, $iCount = 0, $iBlock = null)
|
||||
* @method static array xRevRange($strStream, $strEnd, $strStart, $iCount = 0)
|
||||
* @method static int xTrim($strStream, $iMaxLen, $booApproximate = null)
|
||||
* Pub/sub methods
|
||||
* @method static mixed pSubscribe($patterns, $callback)
|
||||
* @method static mixed publish($channel, $message)
|
||||
* @method static mixed subscribe($channels, $callback)
|
||||
* @method static mixed pubSub($keyword, $argument = null)
|
||||
* Generic methods
|
||||
* @method static mixed rawCommand(...$commandAndArgs)
|
||||
* Transactions methods
|
||||
* @method static \Redis multi()
|
||||
* @method static mixed exec()
|
||||
* @method static mixed discard()
|
||||
* @method static mixed watch($keys)
|
||||
* @method static mixed unwatch($keys)
|
||||
* Scripting methods
|
||||
* @method static mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
|
||||
* @method static mixed evalSha($scriptSha, $numkeys, ...$arguments)
|
||||
* @method static mixed script($command, ...$scripts)
|
||||
* @method static mixed client(...$args)
|
||||
* @method static null|string getLastError()
|
||||
* @method static bool clearLastError()
|
||||
* @method static mixed _prefix($value)
|
||||
* @method static mixed _serialize($value)
|
||||
* @method static mixed _unserialize($value)
|
||||
* Introspection methods
|
||||
* @method static bool isConnected()
|
||||
* @method static mixed getHost()
|
||||
* @method static mixed getPort()
|
||||
* @method static false|int getDbNum()
|
||||
* @method static false|double getTimeout()
|
||||
* @method static mixed getReadTimeout()
|
||||
* @method static mixed getPersistentID()
|
||||
* @method static mixed getAuth()
|
||||
*/
|
||||
class Redis
|
||||
{
|
||||
|
||||
/**
|
||||
* @var RedisManager
|
||||
*/
|
||||
protected static $_instance = null;
|
||||
|
||||
/**
|
||||
* need to install phpredis extension
|
||||
*/
|
||||
const PHPREDIS_CLIENT = 'phpredis';
|
||||
|
||||
/**
|
||||
* need to install the 'predis/predis' packgage.
|
||||
* cmd: composer install predis/predis
|
||||
*/
|
||||
const PREDIS_CLIENT = 'predis';
|
||||
|
||||
/**
|
||||
* Support client collection
|
||||
*/
|
||||
static $_allowClient = [
|
||||
self::PHPREDIS_CLIENT,
|
||||
self::PREDIS_CLIENT
|
||||
];
|
||||
|
||||
/**
|
||||
* @return RedisManager
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
if (!static::$_instance) {
|
||||
$config = \config('redis');
|
||||
$client = $config['client'] ?? self::PHPREDIS_CLIENT;
|
||||
|
||||
if (!\in_array($client, static::$_allowClient)) {
|
||||
$client = self::PHPREDIS_CLIENT;
|
||||
}
|
||||
|
||||
static::$_instance = new RedisManager('', $client, $config);
|
||||
}
|
||||
return static::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return \Illuminate\Redis\Connections\Connection
|
||||
*/
|
||||
public static function connection(string $name = 'default')
|
||||
{
|
||||
static $timers = [];
|
||||
$connection = static::instance()->connection($name);
|
||||
if (!isset($timers[$name])) {
|
||||
$timers[$name] = Worker::getAllWorkers() ? Timer::add(55, function () use ($connection) {
|
||||
$connection->get('ping');
|
||||
}) : 1;
|
||||
if (\class_exists(Dispatcher::class)) {
|
||||
$connection->setEventDispatcher(new Dispatcher());
|
||||
}
|
||||
}
|
||||
return $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public static function __callStatic(string $name, array $arguments)
|
||||
{
|
||||
return static::connection('default')->{$name}(... $arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support;
|
||||
|
||||
/**
|
||||
* Class Request
|
||||
* @package support
|
||||
*/
|
||||
class Request extends \Webman\Http\Request
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support;
|
||||
|
||||
/**
|
||||
* Class Response
|
||||
* @package support
|
||||
*/
|
||||
class Response extends \Webman\Http\Response
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support;
|
||||
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Webman\Exception\NotFoundException;
|
||||
|
||||
/**
|
||||
* Class Translation
|
||||
* @package support
|
||||
* @method static string trans(?string $id, array $parameters = [], string $domain = null, string $locale = null)
|
||||
* @method static void setLocale(string $locale)
|
||||
* @method static string getLocale()
|
||||
*/
|
||||
class Translation
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Translator[]
|
||||
*/
|
||||
protected static $_instance = [];
|
||||
|
||||
/**
|
||||
* @return Translator
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public static function instance(string $plugin = '')
|
||||
{
|
||||
if (!isset(static::$_instance[$plugin])) {
|
||||
$config = \config($plugin ? "plugin.$plugin.translation" : 'translation', []);
|
||||
// Phar support. Compatible with the 'realpath' function in the phar file.
|
||||
if (!$translations_path = \get_realpath($config['path'])) {
|
||||
throw new NotFoundException("File {$config['path']} not found");
|
||||
}
|
||||
|
||||
static::$_instance[$plugin] = $translator = new Translator($config['locale']);
|
||||
$translator->setFallbackLocales($config['fallback_locale']);
|
||||
|
||||
$classes = [
|
||||
'Symfony\Component\Translation\Loader\PhpFileLoader' => [
|
||||
'extension' => '.php',
|
||||
'format' => 'phpfile'
|
||||
],
|
||||
'Symfony\Component\Translation\Loader\PoFileLoader' => [
|
||||
'extension' => '.po',
|
||||
'format' => 'pofile'
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($classes as $class => $opts) {
|
||||
$translator->addLoader($opts['format'], new $class);
|
||||
foreach (\glob($translations_path . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . '*' . $opts['extension']) as $file) {
|
||||
$domain = \basename($file, $opts['extension']);
|
||||
$dir_name = \pathinfo($file, PATHINFO_DIRNAME);
|
||||
$locale = \substr(strrchr($dir_name, DIRECTORY_SEPARATOR), 1);
|
||||
if ($domain && $locale) {
|
||||
$translator->addResource($opts['format'], $file, $locale, $domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return static::$_instance[$plugin];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public static function __callStatic(string $name, array $arguments)
|
||||
{
|
||||
$request = \request();
|
||||
$plugin = $request->plugin ?? '';
|
||||
return static::instance($plugin)->{$name}(... $arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support;
|
||||
|
||||
class View
|
||||
{
|
||||
/**
|
||||
* @param mixed $name
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public static function assign($name, $value = null)
|
||||
{
|
||||
$request = \request();
|
||||
$plugin = $request->plugin ?? '';
|
||||
$handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
|
||||
$handler::assign($name, $value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support\bootstrap;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Events\Dispatcher;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Jenssegers\Mongodb\Connection as MongodbConnection;
|
||||
use support\Db;
|
||||
use Throwable;
|
||||
use Webman\Bootstrap;
|
||||
use Workerman\Timer;
|
||||
use Workerman\Worker;
|
||||
|
||||
/**
|
||||
* Class Laravel
|
||||
* @package support\Bootstrap
|
||||
*/
|
||||
class LaravelDb implements Bootstrap
|
||||
{
|
||||
/**
|
||||
* @param Worker $worker
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function start($worker)
|
||||
{
|
||||
if (!class_exists(Capsule::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$config = \config('database', []);
|
||||
$connections = $config['connections'] ?? [];
|
||||
if (!$connections) {
|
||||
return;
|
||||
}
|
||||
|
||||
$capsule = new Capsule;
|
||||
|
||||
$capsule->getDatabaseManager()->extend('mongodb', function ($config, $name) {
|
||||
$config['name'] = $name;
|
||||
return new MongodbConnection($config);
|
||||
});
|
||||
|
||||
$default = $config['default'] ?? false;
|
||||
if ($default) {
|
||||
$default_config = $connections[$config['default']];
|
||||
$capsule->addConnection($default_config);
|
||||
}
|
||||
|
||||
foreach ($connections as $name => $config) {
|
||||
$capsule->addConnection($config, $name);
|
||||
}
|
||||
|
||||
if (\class_exists(Dispatcher::class)) {
|
||||
$capsule->setEventDispatcher(new Dispatcher(new Container));
|
||||
}
|
||||
|
||||
$capsule->setAsGlobal();
|
||||
|
||||
$capsule->bootEloquent();
|
||||
|
||||
// Heartbeat
|
||||
if ($worker) {
|
||||
Timer::add(55, function () use ($default, $connections, $capsule) {
|
||||
foreach ($capsule->getDatabaseManager()->getConnections() as $connection) {
|
||||
/* @var \Illuminate\Database\MySqlConnection $connection **/
|
||||
if ($connection->getConfig('driver') == 'mysql') {
|
||||
try {
|
||||
$connection->select('select 1');
|
||||
} catch (Throwable $e) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Paginator
|
||||
if (class_exists(Paginator::class)) {
|
||||
if (method_exists(Paginator::class, 'queryStringResolver')) {
|
||||
Paginator::queryStringResolver(function () {
|
||||
$request = request();
|
||||
return $request ? $request->queryString() : null;
|
||||
});
|
||||
}
|
||||
Paginator::currentPathResolver(function () {
|
||||
$request = request();
|
||||
return $request ? $request->path(): '/';
|
||||
});
|
||||
Paginator::currentPageResolver(function ($page_name = 'page') {
|
||||
$request = request();
|
||||
if (!$request) {
|
||||
return 1;
|
||||
}
|
||||
$page = (int)($request->input($page_name, 1));
|
||||
return $page > 0 ? $page : 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support\bootstrap;
|
||||
|
||||
use Webman\Bootstrap;
|
||||
use Workerman\Protocols\Http;
|
||||
use Workerman\Protocols\Http\Session as SessionBase;
|
||||
use Workerman\Worker;
|
||||
|
||||
/**
|
||||
* Class Session
|
||||
* @package support
|
||||
*/
|
||||
class Session implements Bootstrap
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Worker $worker
|
||||
* @return void
|
||||
*/
|
||||
public static function start($worker)
|
||||
{
|
||||
$config = \config('session');
|
||||
if (\property_exists(SessionBase::class, 'name')) {
|
||||
SessionBase::$name = $config['session_name'];
|
||||
} else {
|
||||
Http::sessionName($config['session_name']);
|
||||
}
|
||||
SessionBase::handlerClass($config['handler'], $config['config'][$config['type']]);
|
||||
$map = [
|
||||
'auto_update_timestamp' => 'autoUpdateTimestamp',
|
||||
'cookie_lifetime' => 'cookieLifetime',
|
||||
'gc_probability' => 'gcProbability',
|
||||
'cookie_path' => 'cookiePath',
|
||||
'http_only' => 'httpOnly',
|
||||
'same_site' => 'sameSite',
|
||||
'lifetime' => 'lifetime',
|
||||
'domain' => 'domain',
|
||||
'secure' => 'secure',
|
||||
];
|
||||
foreach ($map as $key => $name) {
|
||||
if (isset($config[$key]) && \property_exists(SessionBase::class, $name)) {
|
||||
SessionBase::${$name} = $config[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support\exception;
|
||||
|
||||
use Exception;
|
||||
use Webman\Http\Response;
|
||||
use Webman\Http\Request;
|
||||
|
||||
/**
|
||||
* Class BusinessException
|
||||
* @package support\exception
|
||||
*/
|
||||
class BusinessException extends Exception
|
||||
{
|
||||
public function render(Request $request): ?Response
|
||||
{
|
||||
if ($request->expectsJson()) {
|
||||
$code = $this->getCode();
|
||||
$json = ['code' => $code ? $code : 500, 'msg' => $this->getMessage()];
|
||||
return new Response(200, ['Content-Type' => 'application/json'],
|
||||
\json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
return new Response(200, [], $this->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support\exception;
|
||||
|
||||
use Throwable;
|
||||
use Webman\Exception\ExceptionHandler;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
|
||||
/**
|
||||
* Class Handler
|
||||
* @package support\exception
|
||||
*/
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
public $dontReport = [
|
||||
BusinessException::class,
|
||||
];
|
||||
|
||||
public function report(Throwable $exception)
|
||||
{
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
public function render(Request $request, Throwable $exception): Response
|
||||
{
|
||||
if(($exception instanceof BusinessException) && ($response = $exception->render($request)))
|
||||
{
|
||||
return $response;
|
||||
}
|
||||
|
||||
return parent::render($request, $exception);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support\view;
|
||||
|
||||
use Jenssegers\Blade\Blade as BladeView;
|
||||
use Webman\View;
|
||||
|
||||
/**
|
||||
* Class Blade
|
||||
* composer require jenssegers/blade
|
||||
* @package support\view
|
||||
*/
|
||||
class Blade implements View
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_vars = [];
|
||||
|
||||
/**
|
||||
* @param string|array $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function assign($name, $value = null)
|
||||
{
|
||||
static::$_vars = \array_merge(static::$_vars, \is_array($name) ? $name : [$name => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @return string
|
||||
*/
|
||||
public static function render(string $template, array $vars, string $app = null)
|
||||
{
|
||||
static $views = [];
|
||||
$request = \request();
|
||||
$plugin = $request->plugin ?? '';
|
||||
$app = $app === null ? $request->app : $app;
|
||||
$config_prefix = $plugin ? "plugin.$plugin." : '';
|
||||
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
|
||||
$key = "{$plugin}-{$request->app}";
|
||||
if (!isset($views[$key])) {
|
||||
$view_path = $app === '' ? "$base_view_path/view" : "$base_view_path/$app/view";
|
||||
$views[$key] = new BladeView($view_path, \runtime_path() . '/views');
|
||||
$extension = \config("{$config_prefix}view.extension");
|
||||
if ($extension) {
|
||||
$extension($views[$key]);
|
||||
}
|
||||
}
|
||||
$vars = \array_merge(static::$_vars, $vars);
|
||||
$content = $views[$key]->render($template, $vars);
|
||||
static::$_vars = [];
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support\view;
|
||||
|
||||
use Webman\View;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class Raw
|
||||
* @package support\view
|
||||
*/
|
||||
class Raw implements View
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_vars = [];
|
||||
|
||||
/**
|
||||
* @param string|array $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function assign($name, $value = null)
|
||||
{
|
||||
static::$_vars = \array_merge(static::$_vars, \is_array($name) ? $name : [$name => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @return false|string
|
||||
*/
|
||||
public static function render(string $template, array $vars, string $app = null)
|
||||
{
|
||||
$request = \request();
|
||||
$plugin = $request->plugin ?? '';
|
||||
$config_prefix = $plugin ? "plugin.$plugin." : '';
|
||||
$view_suffix = \config("{$config_prefix}view.options.view_suffix", 'html');
|
||||
$app = $app === null ? $request->app : $app;
|
||||
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
|
||||
$__template_path__ = $app === '' ? "$base_view_path/view/$template.$view_suffix" : "$base_view_path/$app/view/$template.$view_suffix";
|
||||
|
||||
\extract(static::$_vars);
|
||||
\extract($vars);
|
||||
\ob_start();
|
||||
// Try to include php file.
|
||||
try {
|
||||
include $__template_path__;
|
||||
} catch (Throwable $e) {
|
||||
static::$_vars = [];
|
||||
\ob_end_clean();
|
||||
throw $e;
|
||||
}
|
||||
static::$_vars = [];
|
||||
return \ob_get_clean();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support\view;
|
||||
|
||||
use think\Template;
|
||||
use Webman\View;
|
||||
|
||||
/**
|
||||
* Class Blade
|
||||
* @package support\view
|
||||
*/
|
||||
class ThinkPHP implements View
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_vars = [];
|
||||
|
||||
/**
|
||||
* @param string|array $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function assign($name, $value = null)
|
||||
{
|
||||
static::$_vars = \array_merge(static::$_vars, \is_array($name) ? $name : [$name => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @return false|string
|
||||
*/
|
||||
public static function render(string $template, array $vars, string $app = null)
|
||||
{
|
||||
$request = \request();
|
||||
$plugin = $request->plugin ?? '';
|
||||
$app = $app === null ? $request->app : $app;
|
||||
$config_prefix = $plugin ? "plugin.$plugin." : '';
|
||||
$view_suffix = \config("{$config_prefix}view.options.view_suffix", 'html');
|
||||
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
|
||||
$view_path = $app === '' ? "$base_view_path/view/" : "$base_view_path/$app/view/";
|
||||
$default_options = [
|
||||
'view_path' => $view_path,
|
||||
'cache_path' => \runtime_path() . '/views/',
|
||||
'view_suffix' => $view_suffix
|
||||
];
|
||||
$options = $default_options + \config("{$config_prefix}view.options", []);
|
||||
$views = new Template($options);
|
||||
\ob_start();
|
||||
$vars = \array_merge(static::$_vars, $vars);
|
||||
$views->fetch($template, $vars);
|
||||
$content = \ob_get_clean();
|
||||
static::$_vars = [];
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support\view;
|
||||
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
use Webman\View;
|
||||
|
||||
/**
|
||||
* Class Blade
|
||||
* @package support\view
|
||||
*/
|
||||
class Twig implements View
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $_vars = [];
|
||||
|
||||
/**
|
||||
* @param string|array $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function assign($name, $value = null)
|
||||
{
|
||||
static::$_vars = \array_merge(static::$_vars, \is_array($name) ? $name : [$name => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @return string
|
||||
*/
|
||||
public static function render(string $template, array $vars, string $app = null)
|
||||
{
|
||||
static $views = [];
|
||||
$request = \request();
|
||||
$plugin = $request->plugin ?? '';
|
||||
$app = $app === null ? $request->app : $app;
|
||||
$config_prefix = $plugin ? "plugin.$plugin." : '';
|
||||
$view_suffix = \config("{$config_prefix}view.options.view_suffix", 'html');
|
||||
$key = "{$plugin}-{$request->app}";
|
||||
if (!isset($views[$key])) {
|
||||
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
|
||||
$view_path = $app === '' ? "$base_view_path/view/" : "$base_view_path/$app/view/";
|
||||
$views[$key] = new Environment(new FilesystemLoader($view_path), \config("{$config_prefix}view.options", []));
|
||||
$extension = \config("{$config_prefix}view.extension");
|
||||
if ($extension) {
|
||||
$extension($views[$key]);
|
||||
}
|
||||
}
|
||||
$vars = \array_merge(static::$_vars, $vars);
|
||||
$content = $views[$key]->render("$template.$view_suffix", $vars);
|
||||
static::$_vars = [];
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user