init
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
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"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": ">=8.0",
|
||||
"ext-json": "*",
|
||||
"workerman/workerman": "^4.2.1 || ^5.0.0 || dev-master",
|
||||
"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"
|
||||
},
|
||||
"files": [
|
||||
"./src/support/helpers.php"
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
|
||||
class DisableDefaultRoute
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
|
||||
class Middleware
|
||||
{
|
||||
protected array $middlewares = [];
|
||||
|
||||
public function __construct(...$middlewares)
|
||||
{
|
||||
$this->middlewares = $middlewares;
|
||||
}
|
||||
|
||||
public function getMiddlewares(): array
|
||||
{
|
||||
$middlewares = [];
|
||||
foreach ($this->middlewares as $middleware) {
|
||||
$middlewares[] = [$middleware, 'process'];
|
||||
}
|
||||
return $middlewares;
|
||||
}
|
||||
}
|
||||
+1047
File diff suppressed because it is too large
Load Diff
@@ -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|null $worker
|
||||
* @return mixed
|
||||
*/
|
||||
public static function start(?Worker $worker);
|
||||
}
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
<?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 FilesystemIterator;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use function array_replace_recursive;
|
||||
use function array_reverse;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function key;
|
||||
use function str_replace;
|
||||
|
||||
class Config
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $config = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $configPath = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $loaded = false;
|
||||
|
||||
/**
|
||||
* Load.
|
||||
* @param string $configPath
|
||||
* @param array $excludeFile
|
||||
* @param string|null $key
|
||||
* @return void
|
||||
*/
|
||||
public static function load(string $configPath, array $excludeFile = [], ?string $key = null)
|
||||
{
|
||||
static::$configPath = $configPath;
|
||||
if (!$configPath) {
|
||||
return;
|
||||
}
|
||||
static::$loaded = false;
|
||||
$config = static::loadFromDir($configPath, $excludeFile);
|
||||
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.
|
||||
* @param string $configPath
|
||||
* @param array $excludeFile
|
||||
* @return void
|
||||
* @deprecated
|
||||
*/
|
||||
public static function reload(string $configPath, array $excludeFile = [])
|
||||
{
|
||||
static::load($configPath, $excludeFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear.
|
||||
* @return void
|
||||
*/
|
||||
public static function clear()
|
||||
{
|
||||
static::$config = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* FormatConfig.
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* LoadFromDir.
|
||||
* @param string $configPath
|
||||
* @param array $excludeFile
|
||||
* @return array
|
||||
*/
|
||||
public static function loadFromDir(string $configPath, array $excludeFile = []): array
|
||||
{
|
||||
$allConfig = [];
|
||||
$dirIterator = new RecursiveDirectoryIterator($configPath, FilesystemIterator::FOLLOW_SYMLINKS);
|
||||
$iterator = new RecursiveIteratorIterator($dirIterator);
|
||||
foreach ($iterator as $file) {
|
||||
/** var SplFileInfo $file */
|
||||
if (is_dir($file) || $file->getExtension() != 'php' || in_array($file->getBaseName('.php'), $excludeFile)) {
|
||||
continue;
|
||||
}
|
||||
$appConfigFile = $file->getPath() . '/app.php';
|
||||
if (!is_file($appConfigFile)) {
|
||||
continue;
|
||||
}
|
||||
$relativePath = str_replace($configPath . DIRECTORY_SEPARATOR, '', substr($file, 0, -4));
|
||||
$explode = array_reverse(explode(DIRECTORY_SEPARATOR, $relativePath));
|
||||
if (count($explode) >= 2) {
|
||||
$appConfig = include $appConfigFile;
|
||||
if (empty($appConfig['enable'])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$config = include $file;
|
||||
foreach ($explode as $section) {
|
||||
$tmp = [];
|
||||
$tmp[$section] = $config;
|
||||
$config = $tmp;
|
||||
}
|
||||
$allConfig = array_replace_recursive($allConfig, $config);
|
||||
}
|
||||
return $allConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get.
|
||||
* @param string|null $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get(?string $key = null, mixed $default = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
return static::$config;
|
||||
}
|
||||
$keyArray = explode('.', $key);
|
||||
$value = static::$config;
|
||||
$found = true;
|
||||
foreach ($keyArray 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read.
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function read(string $key, mixed $default = null)
|
||||
{
|
||||
$path = static::$configPath;
|
||||
if ($path === '') {
|
||||
return $default;
|
||||
}
|
||||
$keys = $keyArray = explode('.', $key);
|
||||
foreach ($keyArray 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find.
|
||||
* @param array $keyArray
|
||||
* @param mixed $stack
|
||||
* @param mixed $default
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected static function find(array $keyArray, $stack, $default)
|
||||
{
|
||||
if (!is_array($stack)) {
|
||||
return $default;
|
||||
}
|
||||
$value = $stack;
|
||||
foreach ($keyArray as $index) {
|
||||
if (!isset($value[$index])) {
|
||||
return $default;
|
||||
}
|
||||
$value = $value[$index];
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Webman;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Webman\Exception\NotFoundException;
|
||||
use function array_key_exists;
|
||||
use function class_exists;
|
||||
|
||||
/**
|
||||
* Class Container
|
||||
* @package Webman
|
||||
*/
|
||||
class Container implements ContainerInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $instances = [];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $definitions = [];
|
||||
|
||||
/**
|
||||
* Get.
|
||||
* @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];
|
||||
}
|
||||
|
||||
/**
|
||||
* Has.
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return array_key_exists($name, $this->instances)
|
||||
|| array_key_exists($name, $this->definitions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make.
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
* AddDefinitions.
|
||||
* @param array $definitions
|
||||
* @return $this
|
||||
*/
|
||||
public function addDefinitions(array $definitions): Container
|
||||
{
|
||||
$this->definitions = array_merge($this->definitions, $definitions);
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
<?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 Fiber;
|
||||
use SplObjectStorage;
|
||||
use StdClass;
|
||||
use Swow\Coroutine;
|
||||
use WeakMap;
|
||||
use Workerman\Events\Revolt;
|
||||
use Workerman\Events\Swoole;
|
||||
use Workerman\Events\Swow;
|
||||
use Workerman\Worker;
|
||||
use function property_exists;
|
||||
|
||||
/**
|
||||
* Class Context
|
||||
* @package Webman
|
||||
*/
|
||||
class Context
|
||||
{
|
||||
|
||||
/**
|
||||
* @var SplObjectStorage|WeakMap
|
||||
*/
|
||||
protected static $objectStorage;
|
||||
|
||||
/**
|
||||
* @var StdClass
|
||||
*/
|
||||
protected static $object;
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
if (!static::$objectStorage) {
|
||||
static::$objectStorage = class_exists(WeakMap::class) ? new WeakMap() : new SplObjectStorage();
|
||||
static::$object = new StdClass;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return StdClass
|
||||
*/
|
||||
protected static function getObject(): StdClass
|
||||
{
|
||||
$key = static::getKey();
|
||||
if (!isset(static::$objectStorage[$key])) {
|
||||
static::$objectStorage[$key] = new StdClass;
|
||||
}
|
||||
return static::$objectStorage[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function getKey()
|
||||
{
|
||||
switch (Worker::$eventLoopClass) {
|
||||
case Revolt::class:
|
||||
return Fiber::getCurrent();
|
||||
case Swoole::class:
|
||||
return \Swoole\Coroutine::getContext();
|
||||
case Swow::class:
|
||||
return Coroutine::getCurrent();
|
||||
}
|
||||
return static::$object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $key
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get(?string $key = null)
|
||||
{
|
||||
$obj = static::getObject();
|
||||
if ($key === null) {
|
||||
return $obj;
|
||||
}
|
||||
return $obj->$key ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param $value
|
||||
* @return void
|
||||
*/
|
||||
public static function set(string $key, $value): void
|
||||
{
|
||||
$obj = static::getObject();
|
||||
$obj->$key = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public static function delete(string $key): void
|
||||
{
|
||||
$obj = static::getObject();
|
||||
unset($obj->$key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function has(string $key): bool
|
||||
{
|
||||
$obj = static::getObject();
|
||||
return property_exists($obj, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function destroy(): void
|
||||
{
|
||||
unset(static::$objectStorage[static::getKey()]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?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;
|
||||
use Throwable;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
use function json_encode;
|
||||
|
||||
/**
|
||||
* Class BusinessException
|
||||
* @package support\exception
|
||||
*/
|
||||
class BusinessException extends RuntimeException
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $debug = false;
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
* @param Request $request
|
||||
* @return Response|null
|
||||
*/
|
||||
public function render(Request $request): ?Response
|
||||
{
|
||||
if ($request->expectsJson()) {
|
||||
$code = $this->getCode();
|
||||
$json = ['code' => $code ?: 500, 'msg' => $this->getMessage(), 'data' => $this->data];
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set data.
|
||||
* @param array|null $data
|
||||
* @return array|$this
|
||||
*/
|
||||
public function data(?array $data = null): array|static
|
||||
{
|
||||
if ($data === null) {
|
||||
return $this->data;
|
||||
}
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set debug.
|
||||
* @param bool|null $value
|
||||
* @return $this|bool
|
||||
*/
|
||||
public function debug(?bool $value = null): bool|static
|
||||
{
|
||||
if ($value === null) {
|
||||
return $this->debug;
|
||||
}
|
||||
$this->debug = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data.
|
||||
* @return array
|
||||
*/
|
||||
public function getData(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate message.
|
||||
* @param string $message
|
||||
* @param array $parameters
|
||||
* @param string|null $domain
|
||||
* @param string|null $locale
|
||||
* @return string
|
||||
*/
|
||||
protected function trans(string $message, array $parameters = [], ?string $domain = null, ?string $locale = null): string
|
||||
{
|
||||
$args = [];
|
||||
foreach ($parameters as $key => $parameter) {
|
||||
$args[":$key"] = $parameter;
|
||||
}
|
||||
try {
|
||||
$message = trans($message, $args, $domain, $locale);
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
foreach ($parameters as $key => $value) {
|
||||
$message = str_replace(":$key", $value, $message);
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?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;
|
||||
use function json_encode;
|
||||
use function nl2br;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
if (method_exists($exception, 'render') && ($response = $exception->render($request))) {
|
||||
return $response;
|
||||
}
|
||||
$code = $exception->getCode();
|
||||
if ($request->expectsJson()) {
|
||||
$json = ['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): bool
|
||||
{
|
||||
foreach ($this->dontReport as $type) {
|
||||
if ($e instanceof $type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatible $this->_debug
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool|null
|
||||
*/
|
||||
public function __get(string $name)
|
||||
{
|
||||
if ($name === '_debug') {
|
||||
return $this->debug;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+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 $exception
|
||||
* @return mixed
|
||||
*/
|
||||
public function report(Throwable $exception);
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Throwable $exception
|
||||
* @return Response
|
||||
*/
|
||||
public function render(Request $request, Throwable $exception): 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
|
||||
{
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
<?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 SplFileInfo;
|
||||
use Webman\Exception\FileException;
|
||||
use function chmod;
|
||||
use function is_dir;
|
||||
use function mkdir;
|
||||
use function pathinfo;
|
||||
use function restore_error_handler;
|
||||
use function set_error_handler;
|
||||
use function sprintf;
|
||||
use function strip_tags;
|
||||
use function umask;
|
||||
|
||||
class File extends SplFileInfo
|
||||
{
|
||||
|
||||
/**
|
||||
* Move.
|
||||
* @param string $destination
|
||||
* @return File
|
||||
*/
|
||||
public function move(string $destination): File
|
||||
{
|
||||
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,407 @@
|
||||
<?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\Route\Route;
|
||||
use function current;
|
||||
use function filter_var;
|
||||
use function ip2long;
|
||||
use function is_array;
|
||||
use function strpos;
|
||||
use const FILTER_FLAG_IPV4;
|
||||
use const FILTER_FLAG_NO_PRIV_RANGE;
|
||||
use const FILTER_FLAG_NO_RES_RANGE;
|
||||
use const FILTER_VALIDATE_IP;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isDirty = false;
|
||||
|
||||
/**
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return $this->get() + $this->post();
|
||||
}
|
||||
|
||||
/**
|
||||
* Input
|
||||
* @param string $name
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function input(string $name, mixed $default = null)
|
||||
{
|
||||
return $this->get($name, $this->post($name, $default));
|
||||
}
|
||||
|
||||
/**
|
||||
* Only
|
||||
* @param array $keys
|
||||
* @return array
|
||||
*/
|
||||
public function only(array $keys): array
|
||||
{
|
||||
$all = $this->all();
|
||||
$result = [];
|
||||
foreach ($keys as $key) {
|
||||
if (isset($all[$key])) {
|
||||
$result[$key] = $all[$key];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Except
|
||||
* @param array $keys
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function except(array $keys)
|
||||
{
|
||||
$all = $this->all();
|
||||
foreach ($keys as $key) {
|
||||
unset($all[$key]);
|
||||
}
|
||||
return $all;
|
||||
}
|
||||
|
||||
/**
|
||||
* File
|
||||
* @param string|null $name
|
||||
* @return UploadFile|UploadFile[]|null
|
||||
*/
|
||||
public function file(?string $name = null): array|null|UploadFile
|
||||
{
|
||||
$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);
|
||||
}
|
||||
$uploadFiles = [];
|
||||
foreach ($files as $name => $file) {
|
||||
// Multi files
|
||||
if (is_array(current($file))) {
|
||||
$uploadFiles[$name] = $this->parseFiles($file);
|
||||
} else {
|
||||
$uploadFiles[$name] = $this->parseFile($file);
|
||||
}
|
||||
}
|
||||
return $uploadFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* ParseFile
|
||||
* @param array $file
|
||||
* @return UploadFile
|
||||
*/
|
||||
protected function parseFile(array $file): UploadFile
|
||||
{
|
||||
return new UploadFile($file['tmp_name'], $file['name'], $file['type'], $file['error']);
|
||||
}
|
||||
|
||||
/**
|
||||
* ParseFiles
|
||||
* @param array $files
|
||||
* @return array
|
||||
*/
|
||||
protected function parseFiles(array $files): array
|
||||
{
|
||||
$uploadFiles = [];
|
||||
foreach ($files as $key => $file) {
|
||||
if (is_array(current($file))) {
|
||||
$uploadFiles[$key] = $this->parseFiles($file);
|
||||
} else {
|
||||
$uploadFiles[$key] = $this->parseFile($file);
|
||||
}
|
||||
}
|
||||
return $uploadFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetRemoteIp
|
||||
* @return string
|
||||
*/
|
||||
public function getRemoteIp(): string
|
||||
{
|
||||
return $this->connection ? $this->connection->getRemoteIp() : '0.0.0.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* GetRemotePort
|
||||
* @return int
|
||||
*/
|
||||
public function getRemotePort(): int
|
||||
{
|
||||
return $this->connection ? $this->connection->getRemotePort() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetLocalIp
|
||||
* @return string
|
||||
*/
|
||||
public function getLocalIp(): string
|
||||
{
|
||||
return $this->connection ? $this->connection->getLocalIp() : '0.0.0.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* GetLocalPort
|
||||
* @return int
|
||||
*/
|
||||
public function getLocalPort(): int
|
||||
{
|
||||
return $this->connection ? $this->connection->getLocalPort() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetRealIp
|
||||
* @param bool $safeMode
|
||||
* @return string
|
||||
*/
|
||||
public function getRealIp(bool $safeMode = true): string
|
||||
{
|
||||
$remoteIp = $this->getRemoteIp();
|
||||
if ($safeMode && !static::isIntranetIp($remoteIp)) {
|
||||
return $remoteIp;
|
||||
}
|
||||
$ip = $this->header('x-forwarded-for')
|
||||
?? $this->header('x-real-ip')
|
||||
?? $this->header('client-ip')
|
||||
?? $this->header('x-client-ip')
|
||||
?? $this->header('via')
|
||||
?? $remoteIp;
|
||||
if (is_string($ip)) {
|
||||
$ip = current(explode(',', $ip));
|
||||
}
|
||||
return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : $remoteIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Url
|
||||
* @return string
|
||||
*/
|
||||
public function url(): string
|
||||
{
|
||||
return '//' . $this->host() . $this->path();
|
||||
}
|
||||
|
||||
/**
|
||||
* FullUrl
|
||||
* @return string
|
||||
*/
|
||||
public function fullUrl(): string
|
||||
{
|
||||
return '//' . $this->host() . $this->uri();
|
||||
}
|
||||
|
||||
/**
|
||||
* IsAjax
|
||||
* @return bool
|
||||
*/
|
||||
public function isAjax(): bool
|
||||
{
|
||||
return $this->header('X-Requested-With') === 'XMLHttpRequest';
|
||||
}
|
||||
|
||||
/**
|
||||
* IsGet
|
||||
* @return bool
|
||||
*/
|
||||
public function isGet(): bool
|
||||
{
|
||||
return $this->method() === 'GET';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* IsPost
|
||||
* @return bool
|
||||
*/
|
||||
public function isPost(): bool
|
||||
{
|
||||
return $this->method() === 'POST';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* IsPjax
|
||||
* @return bool
|
||||
*/
|
||||
public function isPjax(): bool
|
||||
{
|
||||
return (bool)$this->header('X-PJAX');
|
||||
}
|
||||
|
||||
/**
|
||||
* ExpectsJson
|
||||
* @return bool
|
||||
*/
|
||||
public function expectsJson(): bool
|
||||
{
|
||||
return ($this->isAjax() && !$this->isPjax()) || $this->acceptJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* AcceptJson
|
||||
* @return bool
|
||||
*/
|
||||
public function acceptJson(): bool
|
||||
{
|
||||
return false !== strpos($this->header('accept', ''), 'json');
|
||||
}
|
||||
|
||||
/**
|
||||
* IsIntranetIp
|
||||
* @param string $ip
|
||||
* @return bool
|
||||
*/
|
||||
public static function isIntranetIp(string $ip): bool
|
||||
{
|
||||
// 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 .
|
||||
$reservedIps = [
|
||||
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
|
||||
];
|
||||
$ipLong = ip2long($ip);
|
||||
foreach ($reservedIps as $ipStart => $ipEnd) {
|
||||
if (($ipLong >= $ipStart) && ($ipLong <= $ipEnd)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set get.
|
||||
* @param array|string $input
|
||||
* @param mixed $value
|
||||
* @return Request
|
||||
*/
|
||||
public function setGet(array|string $input, mixed $value = null): Request
|
||||
{
|
||||
$this->isDirty = true;
|
||||
$input = is_array($input) ? $input : array_merge($this->get(), [$input => $value]);
|
||||
if (isset($this->data)) {
|
||||
$this->data['get'] = $input;
|
||||
} else {
|
||||
$this->_data['get'] = $input;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set post.
|
||||
* @param array|string $input
|
||||
* @param mixed $value
|
||||
* @return Request
|
||||
*/
|
||||
public function setPost(array|string $input, mixed $value = null): Request
|
||||
{
|
||||
$this->isDirty = true;
|
||||
$input = is_array($input) ? $input : array_merge($this->post(), [$input => $value]);
|
||||
if (isset($this->data)) {
|
||||
$this->data['post'] = $input;
|
||||
} else {
|
||||
$this->_data['post'] = $input;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set header.
|
||||
* @param array|string $input
|
||||
* @param mixed $value
|
||||
* @return Request
|
||||
*/
|
||||
public function setHeader(array|string $input, mixed $value = null): Request
|
||||
{
|
||||
$this->isDirty = true;
|
||||
$input = is_array($input) ? $input : array_merge($this->header(), [$input => $value]);
|
||||
if (isset($this->data)) {
|
||||
$this->data['headers'] = $input;
|
||||
} else {
|
||||
$this->_data['headers'] = $input;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
if ($this->isDirty) {
|
||||
unset($this->data['get'], $this->data['post'], $this->data['headers']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?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 Throwable;
|
||||
use Webman\App;
|
||||
use function filemtime;
|
||||
use function gmdate;
|
||||
|
||||
/**
|
||||
* Class Response
|
||||
* @package Webman\Http
|
||||
*/
|
||||
class Response extends \Workerman\Protocols\Http\Response
|
||||
{
|
||||
/**
|
||||
* @var Throwable
|
||||
*/
|
||||
protected $exception = null;
|
||||
|
||||
/**
|
||||
* File
|
||||
* @param string $file
|
||||
* @return $this
|
||||
*/
|
||||
public function file(string $file): Response
|
||||
{
|
||||
if ($this->notModifiedSince($file)) {
|
||||
return $this->withStatus(304);
|
||||
}
|
||||
return $this->withFile($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download
|
||||
* @param string $file
|
||||
* @param string $downloadName
|
||||
* @return $this
|
||||
*/
|
||||
public function download(string $file, string $downloadName = ''): Response
|
||||
{
|
||||
$this->withFile($file);
|
||||
if ($downloadName) {
|
||||
$this->header('Content-Disposition', "attachment; filename=\"$downloadName\"");
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* NotModifiedSince
|
||||
* @param string $file
|
||||
* @return bool
|
||||
*/
|
||||
protected function notModifiedSince(string $file): bool
|
||||
{
|
||||
$ifModifiedSince = App::request()->header('if-modified-since');
|
||||
if ($ifModifiedSince === null || !is_file($file) || !($mtime = filemtime($file))) {
|
||||
return false;
|
||||
}
|
||||
return $ifModifiedSince === gmdate('D, d M Y H:i:s', $mtime) . ' GMT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception
|
||||
* @param Throwable|null $exception
|
||||
* @return Throwable|null
|
||||
*/
|
||||
public function exception(?Throwable $exception = null): ?Throwable
|
||||
{
|
||||
if ($exception) {
|
||||
$this->exception = $exception;
|
||||
}
|
||||
return $this->exception;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?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;
|
||||
use function pathinfo;
|
||||
|
||||
/**
|
||||
* 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 $fileName
|
||||
* @param string $uploadName
|
||||
* @param string $uploadMimeType
|
||||
* @param int $uploadErrorCode
|
||||
*/
|
||||
public function __construct(string $fileName, string $uploadName, string $uploadMimeType, int $uploadErrorCode)
|
||||
{
|
||||
$this->uploadName = $uploadName;
|
||||
$this->uploadMimeType = $uploadMimeType;
|
||||
$this->uploadErrorCode = $uploadErrorCode;
|
||||
parent::__construct($fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetUploadName
|
||||
* @return string
|
||||
*/
|
||||
public function getUploadName(): ?string
|
||||
{
|
||||
return $this->uploadName;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetUploadMimeType
|
||||
* @return string
|
||||
*/
|
||||
public function getUploadMimeType(): ?string
|
||||
{
|
||||
return $this->uploadMimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetUploadExtension
|
||||
* @return string
|
||||
*/
|
||||
public function getUploadExtension(): string
|
||||
{
|
||||
return pathinfo($this->uploadName, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetUploadErrorCode
|
||||
* @return int
|
||||
*/
|
||||
public function getUploadErrorCode(): ?int
|
||||
{
|
||||
return $this->uploadErrorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* IsValid
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid(): bool
|
||||
{
|
||||
return $this->uploadErrorCode === UPLOAD_ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetUploadMineType
|
||||
* @return string
|
||||
* @deprecated
|
||||
*/
|
||||
public function getUploadMineType(): ?string
|
||||
{
|
||||
return $this->uploadMimeType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?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',
|
||||
];
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$parentDir = base_path(dirname($dest));
|
||||
if (!is_dir($parentDir)) {
|
||||
mkdir($parentDir, 0777, true);
|
||||
}
|
||||
$sourceFile = __DIR__ . "/$source";
|
||||
copy_dir($sourceFile, base_path($dest), true);
|
||||
echo "Create $dest\r\n";
|
||||
if (is_file($sourceFile)) {
|
||||
@unlink($sourceFile);
|
||||
}
|
||||
}
|
||||
if (is_file($file = base_path('support/helpers.php'))) {
|
||||
file_put_contents($file, "<?php\n// This file is generated by Webman, please don't modify it.\n");
|
||||
echo "Clear helpers.php\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
<?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 ReflectionAttribute;
|
||||
use Webman\Route\Route;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use RuntimeException;
|
||||
use function array_merge;
|
||||
use function array_reverse;
|
||||
use function is_array;
|
||||
use function method_exists;
|
||||
|
||||
class Middleware
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $instances = [];
|
||||
|
||||
/**
|
||||
* @param mixed $allMiddlewares
|
||||
* @param string $plugin
|
||||
* @return void
|
||||
*/
|
||||
public static function load($allMiddlewares, string $plugin = '')
|
||||
{
|
||||
if (!is_array($allMiddlewares)) {
|
||||
return;
|
||||
}
|
||||
foreach ($allMiddlewares as $appName => $middlewares) {
|
||||
if (!is_array($middlewares)) {
|
||||
throw new RuntimeException('Bad middleware config');
|
||||
}
|
||||
if ($appName === '@') {
|
||||
$plugin = '';
|
||||
}
|
||||
if (strpos($appName, 'plugin.') !== false) {
|
||||
$explode = explode('.', $appName, 4);
|
||||
$plugin = $explode[1];
|
||||
$appName = $explode[2] ?? '';
|
||||
}
|
||||
foreach ($middlewares as $className) {
|
||||
if (method_exists($className, 'process')) {
|
||||
static::$instances[$plugin][$appName][] = [$className, 'process'];
|
||||
} else {
|
||||
// @todo Log
|
||||
echo "middleware $className::process not exsits\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $plugin
|
||||
* @param string $appName
|
||||
* @param string|array|Closure $controller
|
||||
* @param Route|null $route
|
||||
* @param bool $withGlobalMiddleware
|
||||
* @return array
|
||||
*/
|
||||
public static function getMiddleware(string $plugin, string $appName, string|array|Closure $controller, Route|null $route, bool $withGlobalMiddleware = true): array
|
||||
{
|
||||
$isController = is_array($controller) && is_string($controller[0]);
|
||||
$globalMiddleware = $withGlobalMiddleware ? static::$instances['']['@'] ?? [] : [];
|
||||
$appGlobalMiddleware = $withGlobalMiddleware && isset(static::$instances[$plugin]['']) ? static::$instances[$plugin][''] : [];
|
||||
$middlewares = $routeMiddlewares = [];
|
||||
// Route middleware
|
||||
if ($route) {
|
||||
foreach (array_reverse($route->getMiddleware()) as $className) {
|
||||
$routeMiddlewares[] = [$className, 'process'];
|
||||
}
|
||||
}
|
||||
if ($isController && $controller[0] && class_exists($controller[0])) {
|
||||
// Controller middleware annotation
|
||||
$reflectionClass = new ReflectionClass($controller[0]);
|
||||
self::prepareAttributeMiddlewares($middlewares, $reflectionClass);
|
||||
// Controller middleware property
|
||||
if ($reflectionClass->hasProperty('middleware')) {
|
||||
$defaultProperties = $reflectionClass->getDefaultProperties();
|
||||
$middlewaresClasses = $defaultProperties['middleware'];
|
||||
foreach ((array)$middlewaresClasses as $className) {
|
||||
$middlewares[] = [$className, 'process'];
|
||||
}
|
||||
}
|
||||
// Route middleware
|
||||
$middlewares = array_merge($middlewares, $routeMiddlewares);
|
||||
// Method middleware annotation
|
||||
if ($reflectionClass->hasMethod($controller[1])) {
|
||||
self::prepareAttributeMiddlewares($middlewares, $reflectionClass->getMethod($controller[1]));
|
||||
}
|
||||
} else {
|
||||
// Route middleware
|
||||
$middlewares = array_merge($middlewares, $routeMiddlewares);
|
||||
}
|
||||
if ($appName === '') {
|
||||
return array_reverse(array_merge($globalMiddleware, $appGlobalMiddleware, $middlewares));
|
||||
}
|
||||
$appMiddleware = static::$instances[$plugin][$appName] ?? [];
|
||||
return array_reverse(array_merge($globalMiddleware, $appGlobalMiddleware, $appMiddleware, $middlewares));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $middlewares
|
||||
* @param ReflectionClass|ReflectionMethod $reflection
|
||||
* @return void
|
||||
*/
|
||||
private static function prepareAttributeMiddlewares(array &$middlewares, ReflectionClass|ReflectionMethod $reflection): void
|
||||
{
|
||||
$middlewareAttributes = $reflection->getAttributes(Annotation\Middleware::class, ReflectionAttribute::IS_INSTANCEOF);
|
||||
foreach ($middlewareAttributes as $middlewareAttribute) {
|
||||
$middlewareAttributeInstance = $middlewareAttribute->newInstance();
|
||||
$middlewares = array_merge($middlewares, $middlewareAttributeInstance->getMiddlewares());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @deprecated
|
||||
*/
|
||||
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;
|
||||
}
|
||||
+572
@@ -0,0 +1,572 @@
|
||||
<?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 FilesystemIterator;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use Webman\Annotation\DisableDefaultRoute;
|
||||
use Webman\Route\Route as RouteObject;
|
||||
use function array_diff;
|
||||
use function array_values;
|
||||
use function class_exists;
|
||||
use function explode;
|
||||
use function FastRoute\simpleDispatcher;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_callable;
|
||||
use function is_file;
|
||||
use function is_scalar;
|
||||
use function is_string;
|
||||
use function json_encode;
|
||||
use function method_exists;
|
||||
use function strpos;
|
||||
|
||||
/**
|
||||
* 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 RouteObject[]
|
||||
*/
|
||||
protected static $fallbackRoutes = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $fallback = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $nameList = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $groupPrefix = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $disabledDefaultRoutes = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $disabledDefaultRouteControllers = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $disabledDefaultRouteActions = [];
|
||||
|
||||
/**
|
||||
* @var RouteObject[]
|
||||
*/
|
||||
protected static $allRoutes = [];
|
||||
|
||||
/**
|
||||
* @var RouteObject[]
|
||||
*/
|
||||
protected $routes = [];
|
||||
|
||||
/**
|
||||
* @var Route[]
|
||||
*/
|
||||
protected $children = [];
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable|mixed $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function get(string $path, $callback): RouteObject
|
||||
{
|
||||
return static::addRoute('GET', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable|mixed $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function post(string $path, $callback): RouteObject
|
||||
{
|
||||
return static::addRoute('POST', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable|mixed $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function put(string $path, $callback): RouteObject
|
||||
{
|
||||
return static::addRoute('PUT', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable|mixed $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function patch(string $path, $callback): RouteObject
|
||||
{
|
||||
return static::addRoute('PATCH', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable|mixed $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function delete(string $path, $callback): RouteObject
|
||||
{
|
||||
return static::addRoute('DELETE', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable|mixed $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function head(string $path, $callback): RouteObject
|
||||
{
|
||||
return static::addRoute('HEAD', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable|mixed $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function options(string $path, $callback): RouteObject
|
||||
{
|
||||
return static::addRoute('OPTIONS', $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable|mixed $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function any(string $path, $callback): RouteObject
|
||||
{
|
||||
return static::addRoute(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'], $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $method
|
||||
* @param string $path
|
||||
* @param callable|mixed $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
public static function add($method, string $path, $callback): RouteObject
|
||||
{
|
||||
return static::addRoute($method, $path, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|callable $path
|
||||
* @param callable|null $callback
|
||||
* @return static
|
||||
*/
|
||||
public static function group($path, ?callable $callback = null): Route
|
||||
{
|
||||
if ($callback === null) {
|
||||
$callback = $path;
|
||||
$path = '';
|
||||
}
|
||||
$previousGroupPrefix = static::$groupPrefix;
|
||||
static::$groupPrefix = $previousGroupPrefix . $path;
|
||||
$previousInstance = static::$instance;
|
||||
$instance = static::$instance = new static;
|
||||
static::$collector->addGroup($path, $callback);
|
||||
static::$groupPrefix = $previousGroupPrefix;
|
||||
static::$instance = $previousInstance;
|
||||
if ($previousInstance) {
|
||||
$previousInstance->addChild($instance);
|
||||
}
|
||||
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)) {
|
||||
$diffOptions = array_diff($options, ['index', 'create', 'store', 'update', 'show', 'edit', 'destroy', 'recovery']);
|
||||
if (!empty($diffOptions)) {
|
||||
foreach ($diffOptions 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('patch', $options)) static::patch("/$name/{id}", [$controller, 'patch'])->name("$name.patch");
|
||||
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, 'patch')) static::patch("/$name/{id}", [$controller, 'patch'])->name("$name.patch");
|
||||
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(): array
|
||||
{
|
||||
return static::$allRoutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* disableDefaultRoute.
|
||||
*
|
||||
* @param array|string $plugin
|
||||
* @param string|null $app
|
||||
* @return bool
|
||||
*/
|
||||
public static function disableDefaultRoute(array|string $plugin = '', ?string $app = null): bool
|
||||
{
|
||||
// Is [controller action]
|
||||
if (is_array($plugin)) {
|
||||
$controllerAction = $plugin;
|
||||
if (!isset($controllerAction[0]) || !is_string($controllerAction[0]) ||
|
||||
!isset($controllerAction[1]) || !is_string($controllerAction[1])) {
|
||||
return false;
|
||||
}
|
||||
$controller = $controllerAction[0];
|
||||
$action = $controllerAction[1];
|
||||
static::$disabledDefaultRouteActions[$controller][$action] = $action;
|
||||
return true;
|
||||
}
|
||||
// Is plugin
|
||||
if (is_string($plugin) && (preg_match('/^[a-zA-Z0-9_]+$/', $plugin) || $plugin === '')) {
|
||||
if (!isset(static::$disabledDefaultRoutes[$plugin])) {
|
||||
static::$disabledDefaultRoutes[$plugin] = [];
|
||||
}
|
||||
$app = $app ?? '*';
|
||||
static::$disabledDefaultRoutes[$plugin][$app] = $app;
|
||||
return true;
|
||||
}
|
||||
// Is controller
|
||||
if (is_string($plugin) && class_exists($plugin)) {
|
||||
static::$disabledDefaultRouteControllers[$plugin] = $plugin;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $plugin
|
||||
* @param string|null $app
|
||||
* @return bool
|
||||
*/
|
||||
public static function isDefaultRouteDisabled(array|string $plugin = '', ?string $app = null): bool
|
||||
{
|
||||
// Is [controller action]
|
||||
if (is_array($plugin)) {
|
||||
if (!isset($plugin[0]) || !is_string($plugin[0]) ||
|
||||
!isset($plugin[1]) || !is_string($plugin[1])) {
|
||||
return false;
|
||||
}
|
||||
return isset(static::$disabledDefaultRouteActions[$plugin[0]][$plugin[1]]) || static::isDefaultRouteDisabledByAnnotation($plugin[0], $plugin[1]);
|
||||
}
|
||||
// Is plugin
|
||||
if (is_string($plugin) && (preg_match('/^[a-zA-Z0-9_]+$/', $plugin) || $plugin === '')) {
|
||||
$app = $app ?? '*';
|
||||
return isset(static::$disabledDefaultRoutes[$plugin]['*']) || isset(static::$disabledDefaultRoutes[$plugin][$app]);
|
||||
}
|
||||
// Is controller
|
||||
if (is_string($plugin) && class_exists($plugin)) {
|
||||
return isset(static::$disabledDefaultRouteControllers[$plugin]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller
|
||||
* @param string|null $action
|
||||
* @return bool
|
||||
*/
|
||||
protected static function isDefaultRouteDisabledByAnnotation(string $controller, ?string $action = null): bool
|
||||
{
|
||||
if (class_exists($controller)) {
|
||||
$reflectionClass = new ReflectionClass($controller);
|
||||
if ($reflectionClass->getAttributes(DisableDefaultRoute::class, ReflectionAttribute::IS_INSTANCEOF)) {
|
||||
return true;
|
||||
}
|
||||
if ($action && $reflectionClass->hasMethod($action)) {
|
||||
$reflectionMethod = $reflectionClass->getMethod($action);
|
||||
if ($reflectionMethod->getAttributes(DisableDefaultRoute::class, ReflectionAttribute::IS_INSTANCEOF)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $middleware
|
||||
* @return $this
|
||||
*/
|
||||
public function middleware($middleware): Route
|
||||
{
|
||||
foreach ($this->routes as $route) {
|
||||
$route->middleware($middleware);
|
||||
}
|
||||
foreach ($this->getChildren() as $child) {
|
||||
$child->middleware($middleware);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RouteObject $route
|
||||
*/
|
||||
public function collect(RouteObject $route)
|
||||
{
|
||||
$this->routes[] = $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param RouteObject $instance
|
||||
*/
|
||||
public static function setByName(string $name, RouteObject $instance)
|
||||
{
|
||||
static::$nameList[$name] = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return null|RouteObject
|
||||
*/
|
||||
public static function getByName(string $name): ?RouteObject
|
||||
{
|
||||
return static::$nameList[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Route $route
|
||||
* @return void
|
||||
*/
|
||||
public function addChild(Route $route)
|
||||
{
|
||||
$this->children[] = $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Route[]
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param string $path
|
||||
* @return array
|
||||
*/
|
||||
public static function dispatch(string $method, string $path): array
|
||||
{
|
||||
return static::$dispatcher->dispatch($method, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param callable|mixed $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)) {
|
||||
$callStr = is_scalar($callback) ? $callback : 'Closure';
|
||||
echo "Route $path $callStr 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|string $methods
|
||||
* @param string $path
|
||||
* @param callable|mixed $callback
|
||||
* @return RouteObject
|
||||
*/
|
||||
protected static function addRoute($methods, string $path, $callback): RouteObject
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load.
|
||||
* @param mixed $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 $configPath) {
|
||||
$routeConfigFile = $configPath . '/route.php';
|
||||
if (is_file($routeConfigFile)) {
|
||||
require_once $routeConfigFile;
|
||||
}
|
||||
if (!is_dir($pluginConfigPath = $configPath . '/plugin')) {
|
||||
continue;
|
||||
}
|
||||
$dirIterator = new RecursiveDirectoryIterator($pluginConfigPath, FilesystemIterator::FOLLOW_SYMLINKS);
|
||||
$iterator = new RecursiveIteratorIterator($dirIterator);
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->getBaseName('.php') !== 'route') {
|
||||
continue;
|
||||
}
|
||||
$appConfigFile = pathinfo($file, PATHINFO_DIRNAME) . '/app.php';
|
||||
if (!is_file($appConfigFile)) {
|
||||
continue;
|
||||
}
|
||||
$appConfig = include $appConfigFile;
|
||||
if (empty($appConfig['enable'])) {
|
||||
continue;
|
||||
}
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* SetCollector.
|
||||
* @param RouteCollector $route
|
||||
* @return void
|
||||
*/
|
||||
public static function setCollector(RouteCollector $route)
|
||||
{
|
||||
static::$collector = $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback.
|
||||
* @param callable|mixed $callback
|
||||
* @param string $plugin
|
||||
* @return void
|
||||
*/
|
||||
public static function fallback(callable $callback, string $plugin = '')
|
||||
{
|
||||
$route = new RouteObject([], '', $callback);
|
||||
static::$fallbackRoutes[$plugin] = $route;
|
||||
return $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetFallBack.
|
||||
* @param string $plugin
|
||||
* @param int $status
|
||||
* @return callable|null
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public static function getFallback(string $plugin = '', int $status = 404)
|
||||
{
|
||||
if (!isset(static::$fallback[$plugin])) {
|
||||
$callback = null;
|
||||
$route = static::$fallbackRoutes[$plugin] ?? null;
|
||||
static::$fallback[$plugin] = $route ? App::getCallback($plugin, 'NOT_FOUND', $route->getCallback(), ['status' => $status], false, $route) : null;
|
||||
}
|
||||
return static::$fallback[$plugin];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @deprecated
|
||||
*/
|
||||
public static function container()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?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 Webman\Route as Router;
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use function preg_replace_callback;
|
||||
use function str_replace;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name.
|
||||
* @return string|null
|
||||
*/
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name.
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function name(string $name): Route
|
||||
{
|
||||
$this->name = $name;
|
||||
Router::setByName($name, $this);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware.
|
||||
* @param mixed $middleware
|
||||
* @return $this|array
|
||||
*/
|
||||
public function middleware(mixed $middleware = null)
|
||||
{
|
||||
if ($middleware === null) {
|
||||
return $this->middlewares;
|
||||
}
|
||||
$this->middlewares = array_merge($this->middlewares, is_array($middleware) ? array_reverse($middleware) : [$middleware]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetPath.
|
||||
* @return string
|
||||
*/
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetMethods.
|
||||
* @return array
|
||||
*/
|
||||
public function getMethods(): array
|
||||
{
|
||||
return $this->methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetCallback.
|
||||
* @return callable|null
|
||||
*/
|
||||
public function getCallback()
|
||||
{
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetMiddleware.
|
||||
* @return array
|
||||
*/
|
||||
public function getMiddleware(): array
|
||||
{
|
||||
return $this->middlewares;
|
||||
}
|
||||
|
||||
/**
|
||||
* Param.
|
||||
* @param string|null $name
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function param(?string $name = null, mixed $default = null)
|
||||
{
|
||||
if ($name === null) {
|
||||
return $this->params;
|
||||
}
|
||||
return $this->params[$name] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* SetParams.
|
||||
* @param array $params
|
||||
* @return $this
|
||||
*/
|
||||
public function setParams(array $params): Route
|
||||
{
|
||||
$this->params = array_merge($this->params, $params);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Url.
|
||||
* @param array $parameters
|
||||
* @return string
|
||||
*/
|
||||
public function url(array $parameters = []): string
|
||||
{
|
||||
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,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\Session;
|
||||
|
||||
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,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\Session;
|
||||
|
||||
use Workerman\Protocols\Http\Session\RedisSessionHandler as RedisHandler;
|
||||
|
||||
/**
|
||||
* Class FileSessionHandler
|
||||
* @package Webman
|
||||
*/
|
||||
class RedisSessionHandler extends RedisHandler
|
||||
{
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?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 function array_diff;
|
||||
use function array_map;
|
||||
use function scandir;
|
||||
|
||||
/**
|
||||
* Class Util
|
||||
* @package Webman
|
||||
*/
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* ScanDir.
|
||||
* @param string $basePath
|
||||
* @param bool $withBasePath
|
||||
* @return array
|
||||
*/
|
||||
public static function scanDir(string $basePath, bool $withBasePath = true): array
|
||||
{
|
||||
if (!is_dir($basePath)) {
|
||||
return [];
|
||||
}
|
||||
$paths = array_diff(scandir($basePath), array('.', '..')) ?: [];
|
||||
return $withBasePath ? array_map(static function ($path) use ($basePath) {
|
||||
return $basePath . DIRECTORY_SEPARATOR . $path;
|
||||
}, $paths) : $paths;
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?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
|
||||
{
|
||||
/**
|
||||
* Render.
|
||||
* @param string $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @return string
|
||||
*/
|
||||
public static function render(string $template, array $vars, ?string $app = null): string;
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace support;
|
||||
|
||||
use Dotenv\Dotenv;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
use Webman\Config;
|
||||
use Webman\Util;
|
||||
use Workerman\Connection\TcpConnection;
|
||||
use Workerman\Worker;
|
||||
use function base_path;
|
||||
use function call_user_func;
|
||||
use function is_dir;
|
||||
use function opcache_get_status;
|
||||
use function opcache_invalidate;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
class App
|
||||
{
|
||||
/**
|
||||
* Run.
|
||||
* @return void
|
||||
* @throws Throwable
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$appConfigFile = config_path('app.php')) {
|
||||
throw new RuntimeException('Config file not found: app.php');
|
||||
}
|
||||
$appConfig = require $appConfigFile;
|
||||
if ($timezone = $appConfig['default_timezone'] ?? '') {
|
||||
date_default_timezone_set($timezone);
|
||||
}
|
||||
|
||||
static::loadAllConfig(['route', 'container']);
|
||||
|
||||
if (DIRECTORY_SEPARATOR === '\\' && empty(config('server.listen'))) {
|
||||
echo "Please run 'php windows.php' on windows system." . PHP_EOL;
|
||||
exit;
|
||||
}
|
||||
|
||||
$errorReporting = config('app.error_reporting');
|
||||
if (isset($errorReporting)) {
|
||||
error_reporting($errorReporting);
|
||||
}
|
||||
|
||||
$runtimeLogsPath = runtime_path() . DIRECTORY_SEPARATOR . 'logs';
|
||||
if (!file_exists($runtimeLogsPath) || !is_dir($runtimeLogsPath)) {
|
||||
if (!mkdir($runtimeLogsPath, 0777, true)) {
|
||||
throw new RuntimeException("Failed to create runtime logs directory. Please check the permission.");
|
||||
}
|
||||
}
|
||||
|
||||
$runtimeViewsPath = runtime_path() . DIRECTORY_SEPARATOR . 'views';
|
||||
if (!file_exists($runtimeViewsPath) || !is_dir($runtimeViewsPath)) {
|
||||
if (!mkdir($runtimeViewsPath, 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'] ?? false) {
|
||||
$worker = new Worker($config['listen'], $config['context']);
|
||||
$propertyMap = [
|
||||
'name',
|
||||
'count',
|
||||
'user',
|
||||
'group',
|
||||
'reusePort',
|
||||
'transport',
|
||||
'protocol'
|
||||
];
|
||||
foreach ($propertyMap 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 $processName => $config) {
|
||||
if (isset($config['enable']) && $config['enable'] == false) {
|
||||
continue;
|
||||
}
|
||||
worker_start($processName, $config);
|
||||
}
|
||||
foreach (config('plugin', []) as $firm => $projects) {
|
||||
foreach ($projects as $name => $project) {
|
||||
if (!is_array($project)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($project['process'] ?? [] as $processName => $config) {
|
||||
if (isset($config['enable']) && $config['enable'] == false) {
|
||||
continue;
|
||||
}
|
||||
worker_start("plugin.$firm.$name.$processName", $config);
|
||||
}
|
||||
}
|
||||
foreach ($projects['process'] ?? [] as $processName => $config) {
|
||||
if (isset($config['enable']) && $config['enable'] == false) {
|
||||
continue;
|
||||
}
|
||||
worker_start("plugin.$firm.$processName", $config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Worker::runAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* LoadAllConfig.
|
||||
* @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,86 @@
|
||||
<?php
|
||||
|
||||
namespace support;
|
||||
|
||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PdoAdapter;
|
||||
use Symfony\Component\Cache\Psr16Cache;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* 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 $instances = [];
|
||||
|
||||
/***
|
||||
* @param string|null $name
|
||||
* @return Psr16Cache
|
||||
*/
|
||||
public static function store(?string $name = null): Psr16Cache
|
||||
{
|
||||
$name = $name ?: config('cache.default', 'redis');
|
||||
$stores = !config('cache') ? [
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => 'default'
|
||||
],
|
||||
] : config('cache.stores', []);
|
||||
if (!isset($stores[$name])) {
|
||||
throw new InvalidArgumentException("cache.store.$name is not defined. Please check config/cache.php");
|
||||
}
|
||||
if (!isset(static::$instances[$name])) {
|
||||
$driver = $stores[$name]['driver'];
|
||||
switch ($driver) {
|
||||
case 'redis':
|
||||
$client = Redis::connection($stores[$name]['connection'])->client();
|
||||
$adapter = new RedisAdapter($client);
|
||||
break;
|
||||
case 'file':
|
||||
$adapter = new FilesystemAdapter('', 0, $stores[$name]['path']);
|
||||
break;
|
||||
case 'array':
|
||||
$adapter = new ArrayAdapter(0, $stores[$name]['serialize'] ?? false, 0, 0);
|
||||
break;
|
||||
/**
|
||||
* Pdo can not reconnect when the connection is lost. So we can not use pdo as cache.
|
||||
*/
|
||||
/*case 'database':
|
||||
$adapter = new PdoAdapter(Db::connection($stores[$name]['connection'])->getPdo());
|
||||
break;*/
|
||||
default:
|
||||
throw new InvalidArgumentException("cache.store.$name.driver=$driver is not supported.");
|
||||
}
|
||||
static::$instances[$name] = new Psr16Cache($adapter);
|
||||
}
|
||||
|
||||
return static::$instances[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public static function __callStatic($name, $arguments)
|
||||
{
|
||||
return static::store()->{$name}(... $arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?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 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
|
||||
{
|
||||
/**
|
||||
* Instance
|
||||
* @param string $plugin
|
||||
* @return array|mixed|void|null
|
||||
*/
|
||||
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,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 support;
|
||||
|
||||
/**
|
||||
* Class Context
|
||||
* @package Webman
|
||||
*/
|
||||
class Context extends \Webman\Context
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?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 Closure;
|
||||
use Illuminate\Database\Capsule\Manager;
|
||||
use Illuminate\Database\Connection;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* @return Manager
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Connection[]
|
||||
*/
|
||||
public static function getConnections()
|
||||
{
|
||||
return static::$instance->getDatabaseManager()->getConnections();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<?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;
|
||||
use function array_values;
|
||||
use function config;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* 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 = [];
|
||||
|
||||
/**
|
||||
* Channel.
|
||||
* @param string $name
|
||||
* @return Logger
|
||||
*/
|
||||
public static function channel(string $name = 'default'): Logger
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handlers.
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler.
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processors.
|
||||
* @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()->{$name}(... $arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
<?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 Closure;
|
||||
use Illuminate\Contracts\Pagination\CursorPaginator;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Contracts\Pagination\Paginator;
|
||||
use Illuminate\Database\Eloquent\Model as BaseModel;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Database\Query\Expression;
|
||||
use Illuminate\Database\Query\Grammars\Grammar;
|
||||
use Illuminate\Database\Query\Processors\Processor;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\LazyCollection;
|
||||
|
||||
/**
|
||||
* @method static BaseModel make($attributes = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withGlobalScope($identifier, $scope)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withoutGlobalScope($scope)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withoutGlobalScopes($scopes = null)
|
||||
* @method static array removedScopes()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static whereKey($id)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static whereKeyNot($id)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static where($column, $operator = null, $value = null, $boolean = 'and')
|
||||
* @method static BaseModel|null firstWhere($column, $operator = null, $value = null, $boolean = 'and')
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static orWhere($column, $operator = null, $value = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static latest($column = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static oldest($column = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Collection|static hydrate($items)
|
||||
* @method static \Illuminate\Database\Eloquent\Collection|static fromQuery($query, $bindings = [])
|
||||
* @method static BaseModel|\Illuminate\Database\Eloquent\Collection|static[]|static|null find($id, $columns = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Collection|static findMany($ids, $columns = [])
|
||||
* @method static BaseModel|\Illuminate\Database\Eloquent\Collection|static|static[] findOrFail($id, $columns = [])
|
||||
* @method static BaseModel|static findOrNew($id, $columns = [])
|
||||
* @method static BaseModel|static firstOrNew($attributes = [], $values = [])
|
||||
* @method static BaseModel|static firstOrCreate($attributes = [], $values = [])
|
||||
* @method static BaseModel|static updateOrCreate($attributes, $values = [])
|
||||
* @method static BaseModel|static firstOrFail($columns = [])
|
||||
* @method static BaseModel|static|mixed firstOr($columns = [], $callback = null)
|
||||
* @method static BaseModel sole($columns = [])
|
||||
* @method static mixed value($column)
|
||||
* @method static \Illuminate\Database\Eloquent\Collection[]|static[] get($columns = [])
|
||||
* @method static BaseModel[]|static[] getModels($columns = [])
|
||||
* @method static array eagerLoadRelations($models)
|
||||
* @method static LazyCollection cursor()
|
||||
* @method static Collection pluck($column, $key = null)
|
||||
* @method static LengthAwarePaginator paginate($perPage = null, $columns = [], $pageName = 'page', $page = null)
|
||||
* @method static Paginator simplePaginate($perPage = null, $columns = [], $pageName = 'page', $page = null)
|
||||
* @method static CursorPaginator cursorPaginate($perPage = null, $columns = [], $cursorName = 'cursor', $cursor = null)
|
||||
* @method static BaseModel|$this create($attributes = [])
|
||||
* @method static BaseModel|$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|static without($relations)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withOnly($relations)
|
||||
* @method static BaseModel newModelInstance($attributes = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withCasts($casts)
|
||||
* @method static Builder getQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static setQuery($query)
|
||||
* @method static Builder toBase()
|
||||
* @method static array getEagerLoads()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static setEagerLoads($eagerLoad)
|
||||
* @method static BaseModel getModel()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static 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|static has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static orHas($relation, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static doesntHave($relation, $boolean = 'and', $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static orDoesntHave($relation)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static whereHas($relation, $callback = null, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static orWhereHas($relation, $callback = null, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static whereDoesntHave($relation, $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static orWhereDoesntHave($relation, $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static hasMorph($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static orHasMorph($relation, $types, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static doesntHaveMorph($relation, $types, $boolean = 'and', $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static orDoesntHaveMorph($relation, $types)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static whereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static orWhereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static whereDoesntHaveMorph($relation, $types, $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static orWhereDoesntHaveMorph($relation, $types, $callback = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withAggregate($relations, $column, $function = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withCount($relations)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withMax($relation, $column)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withMin($relation, $column)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withSum($relation, $column)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withAvg($relation, $column)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static withExists($relation)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static mergeConstraintsFrom($from)
|
||||
* @method static Collection explain()
|
||||
* @method static bool chunk($count, $callback)
|
||||
* @method static 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 LazyCollection lazy($chunkSize = 1000)
|
||||
* @method static LazyCollection lazyById($chunkSize = 1000, $column = null, $alias = null)
|
||||
* @method static BaseModel|object|static|null first($columns = [])
|
||||
* @method static BaseModel|object|null baseSole($columns = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static tap($callback)
|
||||
* @method static mixed when($value, $callback, $default = null)
|
||||
* @method static mixed unless($value, $callback, $default = null)
|
||||
* @method static Builder select($columns = [])
|
||||
* @method static Builder selectSub($query, $as)
|
||||
* @method static Builder selectRaw($expression, $bindings = [])
|
||||
* @method static Builder fromSub($query, $as)
|
||||
* @method static Builder fromRaw($expression, $bindings = [])
|
||||
* @method static Builder addSelect($column)
|
||||
* @method static Builder distinct()
|
||||
* @method static Builder from($table, $as = null)
|
||||
* @method static Builder join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false)
|
||||
* @method static Builder joinWhere($table, $first, $operator, $second, $type = 'inner')
|
||||
* @method static Builder joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false)
|
||||
* @method static Builder leftJoin($table, $first, $operator = null, $second = null)
|
||||
* @method static Builder leftJoinWhere($table, $first, $operator, $second)
|
||||
* @method static Builder leftJoinSub($query, $as, $first, $operator = null, $second = null)
|
||||
* @method static Builder rightJoin($table, $first, $operator = null, $second = null)
|
||||
* @method static Builder rightJoinWhere($table, $first, $operator, $second)
|
||||
* @method static Builder rightJoinSub($query, $as, $first, $operator = null, $second = null)
|
||||
* @method static Builder crossJoin($table, $first = null, $operator = null, $second = null)
|
||||
* @method static Builder crossJoinSub($query, $as)
|
||||
* @method static void mergeWheres($wheres, $bindings)
|
||||
* @method static array prepareValueAndOperator($value, $operator, $useDefault = false)
|
||||
* @method static Builder whereColumn($first, $operator = null, $second = null, $boolean = 'and')
|
||||
* @method static Builder orWhereColumn($first, $operator = null, $second = null)
|
||||
* @method static Builder whereRaw($sql, $bindings = [], $boolean = 'and')
|
||||
* @method static Builder orWhereRaw($sql, $bindings = [])
|
||||
* @method static Builder whereIn($column, $values, $boolean = 'and', $not = false)
|
||||
* @method static Builder orWhereIn($column, $values)
|
||||
* @method static Builder whereNotIn($column, $values, $boolean = 'and')
|
||||
* @method static Builder orWhereNotIn($column, $values)
|
||||
* @method static Builder whereIntegerInRaw($column, $values, $boolean = 'and', $not = false)
|
||||
* @method static Builder orWhereIntegerInRaw($column, $values)
|
||||
* @method static Builder whereIntegerNotInRaw($column, $values, $boolean = 'and')
|
||||
* @method static Builder orWhereIntegerNotInRaw($column, $values)
|
||||
* @method static Builder whereNull($columns, $boolean = 'and', $not = false)
|
||||
* @method static Builder orWhereNull($column)
|
||||
* @method static Builder whereNotNull($columns, $boolean = 'and')
|
||||
* @method static Builder whereBetween($column, $values, $boolean = 'and', $not = false)
|
||||
* @method static Builder whereBetweenColumns($column, $values, $boolean = 'and', $not = false)
|
||||
* @method static Builder orWhereBetween($column, $values)
|
||||
* @method static Builder orWhereBetweenColumns($column, $values)
|
||||
* @method static Builder whereNotBetween($column, $values, $boolean = 'and')
|
||||
* @method static Builder whereNotBetweenColumns($column, $values, $boolean = 'and')
|
||||
* @method static Builder orWhereNotBetween($column, $values)
|
||||
* @method static Builder orWhereNotBetweenColumns($column, $values)
|
||||
* @method static Builder orWhereNotNull($column)
|
||||
* @method static Builder whereDate($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static Builder orWhereDate($column, $operator, $value = null)
|
||||
* @method static Builder whereTime($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static Builder orWhereTime($column, $operator, $value = null)
|
||||
* @method static Builder whereDay($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static Builder orWhereDay($column, $operator, $value = null)
|
||||
* @method static Builder whereMonth($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static Builder orWhereMonth($column, $operator, $value = null)
|
||||
* @method static Builder whereYear($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static Builder orWhereYear($column, $operator, $value = null)
|
||||
* @method static Builder whereNested($callback, $boolean = 'and')
|
||||
* @method static Builder forNestedWhere()
|
||||
* @method static Builder addNestedWhereQuery($query, $boolean = 'and')
|
||||
* @method static Builder whereExists($callback, $boolean = 'and', $not = false)
|
||||
* @method static Builder orWhereExists($callback, $not = false)
|
||||
* @method static Builder whereNotExists($callback, $boolean = 'and')
|
||||
* @method static Builder orWhereNotExists($callback)
|
||||
* @method static Builder addWhereExistsQuery($query, $boolean = 'and', $not = false)
|
||||
* @method static Builder whereRowValues($columns, $operator, $values, $boolean = 'and')
|
||||
* @method static Builder orWhereRowValues($columns, $operator, $values)
|
||||
* @method static Builder whereJsonContains($column, $value, $boolean = 'and', $not = false)
|
||||
* @method static Builder orWhereJsonContains($column, $value)
|
||||
* @method static Builder whereJsonDoesntContain($column, $value, $boolean = 'and')
|
||||
* @method static Builder orWhereJsonDoesntContain($column, $value)
|
||||
* @method static Builder whereJsonLength($column, $operator, $value = null, $boolean = 'and')
|
||||
* @method static Builder orWhereJsonLength($column, $operator, $value = null)
|
||||
* @method static Builder dynamicWhere($method, $parameters)
|
||||
* @method static Builder groupBy(...$groups)
|
||||
* @method static Builder groupByRaw($sql, $bindings = [])
|
||||
* @method static Builder having($column, $operator = null, $value = null, $boolean = 'and')
|
||||
* @method static Builder orHaving($column, $operator = null, $value = null)
|
||||
* @method static Builder havingBetween($column, $values, $boolean = 'and', $not = false)
|
||||
* @method static Builder havingRaw($sql, $bindings = [], $boolean = 'and')
|
||||
* @method static Builder orHavingRaw($sql, $bindings = [])
|
||||
* @method static Builder orderBy($column, $direction = 'asc')
|
||||
* @method static Builder orderByDesc($column)
|
||||
* @method static Builder inRandomOrder($seed = '')
|
||||
* @method static Builder orderByRaw($sql, $bindings = [])
|
||||
* @method static Builder skip($value)
|
||||
* @method static Builder offset($value)
|
||||
* @method static Builder take($value)
|
||||
* @method static Builder limit($value)
|
||||
* @method static Builder forPage($page, $perPage = 15)
|
||||
* @method static Builder forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id')
|
||||
* @method static Builder forPageAfterId($perPage = 15, $lastId = 0, $column = 'id')
|
||||
* @method static Builder reorder($column = null, $direction = 'asc')
|
||||
* @method static Builder union($query, $all = false)
|
||||
* @method static Builder unionAll($query)
|
||||
* @method static Builder lock($value = true)
|
||||
* @method static Builder lockForUpdate()
|
||||
* @method static Builder sharedLock()
|
||||
* @method static 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 Expression raw($value)
|
||||
* @method static array getBindings()
|
||||
* @method static array getRawBindings()
|
||||
* @method static Builder setBindings($bindings, $type = 'where')
|
||||
* @method static Builder addBinding($value, $type = 'where')
|
||||
* @method static Builder mergeBindings($query)
|
||||
* @method static array cleanBindings($bindings)
|
||||
* @method static Processor getProcessor()
|
||||
* @method static Grammar getGrammar()
|
||||
* @method static Builder useWritePdo()
|
||||
* @method static static cloneWithout($properties)
|
||||
* @method static static cloneWithoutBindings($except)
|
||||
* @method static 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,102 @@
|
||||
<?php
|
||||
|
||||
namespace support;
|
||||
|
||||
use function defined;
|
||||
use function is_callable;
|
||||
use function is_file;
|
||||
use function method_exists;
|
||||
|
||||
class Plugin
|
||||
{
|
||||
/**
|
||||
* Install.
|
||||
* @param mixed $event
|
||||
* @return void
|
||||
*/
|
||||
public static function install($event)
|
||||
{
|
||||
static::findHelper();
|
||||
$psr4 = static::getPsr4($event);
|
||||
foreach ($psr4 as $namespace => $path) {
|
||||
$pluginConst = "\\{$namespace}Install::WEBMAN_PLUGIN";
|
||||
if (!defined($pluginConst)) {
|
||||
continue;
|
||||
}
|
||||
$installFunction = "\\{$namespace}Install::install";
|
||||
if (is_callable($installFunction)) {
|
||||
$installFunction(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update.
|
||||
* @param mixed $event
|
||||
* @return void
|
||||
*/
|
||||
public static function update($event)
|
||||
{
|
||||
static::findHelper();
|
||||
$psr4 = static::getPsr4($event);
|
||||
foreach ($psr4 as $namespace => $path) {
|
||||
$pluginConst = "\\{$namespace}Install::WEBMAN_PLUGIN";
|
||||
if (!defined($pluginConst)) {
|
||||
continue;
|
||||
}
|
||||
$updateFunction = "\\{$namespace}Install::update";
|
||||
if (is_callable($updateFunction)) {
|
||||
$updateFunction();
|
||||
continue;
|
||||
}
|
||||
$installFunction = "\\{$namespace}Install::install";
|
||||
if (is_callable($installFunction)) {
|
||||
$installFunction(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall.
|
||||
* @param mixed $event
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall($event)
|
||||
{
|
||||
static::findHelper();
|
||||
$psr4 = static::getPsr4($event);
|
||||
foreach ($psr4 as $namespace => $path) {
|
||||
$pluginConst = "\\{$namespace}Install::WEBMAN_PLUGIN";
|
||||
if (!defined($pluginConst)) {
|
||||
continue;
|
||||
}
|
||||
$uninstallFunction = "\\{$namespace}Install::uninstall";
|
||||
if (is_callable($uninstallFunction)) {
|
||||
$uninstallFunction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get psr-4 info
|
||||
*
|
||||
* @param mixed $event
|
||||
* @return array
|
||||
*/
|
||||
protected static function getPsr4($event)
|
||||
{
|
||||
$operation = $event->getOperation();
|
||||
$autoload = method_exists($operation, 'getPackage') ? $operation->getPackage()->getAutoload() : $operation->getTargetPackage()->getAutoload();
|
||||
return $autoload['psr-4'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* FindHelper.
|
||||
* @return void
|
||||
*/
|
||||
protected static function findHelper()
|
||||
{
|
||||
// Plugin.php in webman
|
||||
require_once __DIR__ . '/helpers.php';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
<?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\Connections\Connection;
|
||||
use Illuminate\Redis\RedisManager;
|
||||
use Workerman\Timer;
|
||||
use Workerman\Worker;
|
||||
use function class_exists;
|
||||
use function config;
|
||||
use function in_array;
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
];
|
||||
|
||||
/**
|
||||
* The Redis server configurations.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $config = [];
|
||||
|
||||
/**
|
||||
* Static timers facilitate deletion during callbacks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $timers = [];
|
||||
|
||||
/**
|
||||
* The number of seconds an idle connection will be terminated.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $idle_time = 0;
|
||||
|
||||
/**
|
||||
* @return RedisManager
|
||||
*/
|
||||
public static function instance(): ?RedisManager
|
||||
{
|
||||
if (!static::$instance) {
|
||||
$config = config('redis');
|
||||
$client = $config['client'] ?? self::PHPREDIS_CLIENT;
|
||||
|
||||
if (!in_array($client, static::$allowClient)) {
|
||||
$client = self::PHPREDIS_CLIENT;
|
||||
}
|
||||
|
||||
static::$config = $config;
|
||||
static::$instance = new RedisManager('', $client, $config);
|
||||
}
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connection.
|
||||
* @param string $name
|
||||
* @return Connection|\Redis
|
||||
*/
|
||||
public static function connection(string $name = 'default'): Connection
|
||||
{
|
||||
if (!empty(static::$config[$name]['idle_timeout'])) {
|
||||
static::$idle_time = time();
|
||||
}
|
||||
|
||||
$connection = static::instance()->connection($name);
|
||||
if (!isset(static::$timers[$name])) {
|
||||
static::$timers[$name] = Worker::getAllWorkers() ? Timer::add(55, function () use ($connection, $name) {
|
||||
if (!empty(static::$config[$name]['idle_timeout'])
|
||||
&& time() - static::$idle_time > static::$config[$name]['idle_timeout']) {
|
||||
Timer::del(static::$timers[$name]);
|
||||
unset(static::$timers[$name]);
|
||||
return $connection->client()->close();
|
||||
}
|
||||
|
||||
$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()->{$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,107 @@
|
||||
<?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 FilesystemIterator;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use RegexIterator;
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Webman\Exception\NotFoundException;
|
||||
use function basename;
|
||||
use function config;
|
||||
use function get_realpath;
|
||||
use function pathinfo;
|
||||
use function request;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* 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 = [];
|
||||
|
||||
/**
|
||||
* Instance.
|
||||
* @param string $plugin
|
||||
* @return Translator
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public static function instance(string $plugin = ''): Translator
|
||||
{
|
||||
if (!isset(static::$instance[$plugin])) {
|
||||
$config = config($plugin ? "plugin.$plugin.translation" : 'translation', []);
|
||||
$paths = (array)($config['path'] ?? []);
|
||||
|
||||
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 ($paths as $path) {
|
||||
// Phar support. Compatible with the 'realpath' function in the phar file.
|
||||
if (!$translationsPath = get_realpath($path)) {
|
||||
throw new NotFoundException("File {$path} not found");
|
||||
}
|
||||
|
||||
foreach ($classes as $class => $opts) {
|
||||
$translator->addLoader($opts['format'], new $class);
|
||||
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($translationsPath, FilesystemIterator::SKIP_DOTS));
|
||||
$files = new RegexIterator($iterator, '/^.+' . preg_quote($opts['extension']) . '$/i', RegexIterator::GET_MATCH);
|
||||
foreach ($files as $file) {
|
||||
$file = $file[0];
|
||||
$domain = basename($file, $opts['extension']);
|
||||
$dirName = pathinfo($file, PATHINFO_DIRNAME);
|
||||
$locale = substr(strrchr($dirName, 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,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 function config;
|
||||
use function request;
|
||||
|
||||
class View
|
||||
{
|
||||
/**
|
||||
* Assign.
|
||||
* @param mixed $name
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public static function assign($name, mixed $value = null)
|
||||
{
|
||||
$request = request();
|
||||
$plugin = $request->plugin ?? '';
|
||||
$handler = config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
|
||||
$handler::assign($name, $value);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
|
||||
class DisableDefaultRoute extends \Webman\Annotation\DisableDefaultRoute
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
|
||||
class Middleware extends \Webman\Annotation\Middleware
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?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 as IlluminateContainer;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Illuminate\Database\MySqlConnection;
|
||||
use Illuminate\Events\Dispatcher;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Pagination\CursorPaginator;
|
||||
use Illuminate\Pagination\Cursor;
|
||||
use Jenssegers\Mongodb\Connection as JenssegersMongodbConnection;
|
||||
use MongoDB\Laravel\Connection as LaravelMongodbConnection;
|
||||
use support\Container;
|
||||
use Throwable;
|
||||
use Webman\Bootstrap;
|
||||
use Workerman\Timer;
|
||||
use Workerman\Worker;
|
||||
use function class_exists;
|
||||
use function config;
|
||||
|
||||
/**
|
||||
* Class Laravel
|
||||
* @package support\Bootstrap
|
||||
*/
|
||||
class LaravelDb implements Bootstrap
|
||||
{
|
||||
/**
|
||||
* @param Worker|null $worker
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function start(?Worker $worker)
|
||||
{
|
||||
if (!class_exists(Capsule::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$config = config('database', []);
|
||||
$connections = $config['connections'] ?? [];
|
||||
if (!$connections) {
|
||||
return;
|
||||
}
|
||||
|
||||
$capsule = new Capsule(IlluminateContainer::getInstance());
|
||||
|
||||
$capsule->getDatabaseManager()->extend('mongodb', function ($config, $name) {
|
||||
$config['name'] = $name;
|
||||
return class_exists(LaravelMongodbConnection::class) ? new LaravelMongodbConnection($config) : new JenssegersMongodbConnection($config);
|
||||
});
|
||||
|
||||
$default = $config['default'] ?? false;
|
||||
$persistent = $config['persistent'] ?? true;
|
||||
if ($default) {
|
||||
$defaultConfig = $connections[$config['default']] ?? false;
|
||||
if ($defaultConfig) {
|
||||
$capsule->addConnection($defaultConfig);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($connections as $name => $config) {
|
||||
$capsule->addConnection($config, $name);
|
||||
}
|
||||
|
||||
if (class_exists(Dispatcher::class) && !$capsule->getEventDispatcher()) {
|
||||
$capsule->setEventDispatcher(Container::make(Dispatcher::class, [IlluminateContainer::getInstance()]));
|
||||
}
|
||||
|
||||
$capsule->setAsGlobal();
|
||||
|
||||
$capsule->bootEloquent();
|
||||
|
||||
// Heartbeat
|
||||
if ($worker && $persistent) {
|
||||
Timer::add(55, function () use ($default, $connections, $capsule) {
|
||||
foreach ($capsule->getDatabaseManager()->getConnections() as $connection) {
|
||||
/* @var MySqlConnection $connection **/
|
||||
if ($connection->getConfig('driver') == 'mysql' && $connection->getRawPdo()) {
|
||||
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 ($pageName = 'page') {
|
||||
$request = request();
|
||||
if (!$request) {
|
||||
return 1;
|
||||
}
|
||||
$page = (int)($request->input($pageName, 1));
|
||||
return $page > 0 ? $page : 1;
|
||||
});
|
||||
if (class_exists(CursorPaginator::class)) {
|
||||
CursorPaginator::currentCursorResolver(function ($cursorName = 'cursor') {
|
||||
return Cursor::fromEncoded(request()->input($cursorName));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?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;
|
||||
use function config;
|
||||
use function property_exists;
|
||||
|
||||
/**
|
||||
* Class Session
|
||||
* @package support
|
||||
*/
|
||||
class Session implements Bootstrap
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Worker|null $worker
|
||||
* @return void
|
||||
*/
|
||||
public static function start(?Worker $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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -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\exception;
|
||||
|
||||
/**
|
||||
* Class BusinessException
|
||||
* @package support\exception
|
||||
*/
|
||||
class BusinessException extends \Webman\Exception\BusinessException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?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;
|
||||
use Webman\Exception\BusinessException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
return parent::render($request, $exception);
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace support\exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class InputTypeException extends PageNotFoundException
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $template = '/app/view/400';
|
||||
|
||||
/**
|
||||
* InputTypeException constructor.
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = 'Input :parameter must be of type :exceptType, :actualType given', int $code = 400, ?Throwable $previous = null) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace support\exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class InputValueException extends PageNotFoundException
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $template = '/app/view/400';
|
||||
|
||||
/**
|
||||
* InputTypeException constructor.
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = 'Input :parameter is invalid.', int $code = 400, ?Throwable $previous = null) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace support\exception;
|
||||
|
||||
use Throwable;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
|
||||
class MissingInputException extends PageNotFoundException
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $template = '/app/view/400';
|
||||
|
||||
/**
|
||||
* MissingInputException constructor.
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = 'Missing input parameter :parameter', int $code = 400, ?Throwable $previous = null) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
* @param Request $request
|
||||
* @return Response|null
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function render(Request $request): ?Response
|
||||
{
|
||||
$code = $this->getCode() ?: 404;
|
||||
$debug = config($request->plugin ? "plugin.$request->plugin.app.debug" : 'app.debug');
|
||||
$data = $debug ? $this->data : ['parameter' => ''];
|
||||
$message = $this->trans($this->getMessage(), $data);
|
||||
if ($request->expectsJson()) {
|
||||
$json = ['code' => $code, 'msg' => $message, 'data' => $data];
|
||||
return new Response(200, ['Content-Type' => 'application/json'],
|
||||
json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
return new Response($code, [], $this->html($message));
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?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;
|
||||
|
||||
class NotFoundException extends BusinessException
|
||||
{
|
||||
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
<?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\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
|
||||
class PageNotFoundException extends NotFoundException
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $template = '/app/view/404';
|
||||
|
||||
/**
|
||||
* PageNotFoundException constructor.
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = '404 Not Found', int $code = 404, ?Throwable $previous = null) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
* @param Request $request
|
||||
* @return Response|null
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function render(Request $request): ?Response
|
||||
{
|
||||
$code = $this->getCode() ?: 404;
|
||||
$data = $this->data;
|
||||
$message = $this->trans($this->getMessage(), $data);
|
||||
if ($request->expectsJson()) {
|
||||
$json = ['code' => $code, 'msg' => $message, 'data' => $data];
|
||||
return new Response(200, ['Content-Type' => 'application/json'],
|
||||
json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
return new Response($code, [], $this->html($message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML representation of the exception.
|
||||
* @param string $message
|
||||
* @return string
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected function html(string $message): string
|
||||
{
|
||||
$message = htmlspecialchars($message);
|
||||
if (is_file(base_path("$this->template.html"))) {
|
||||
return raw_view($this->template, ['message' => $message])->rawBody();
|
||||
}
|
||||
return <<<EOF
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>$message</title>
|
||||
<style>
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 class="center">$message</h1>
|
||||
<hr>
|
||||
<div class="center">webman</div>
|
||||
</body>
|
||||
</html>
|
||||
EOF;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,683 @@
|
||||
<?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
|
||||
*/
|
||||
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use support\Translation;
|
||||
use support\view\Blade;
|
||||
use support\view\Raw;
|
||||
use support\view\ThinkPHP;
|
||||
use support\view\Twig;
|
||||
use Twig\Error\LoaderError;
|
||||
use Twig\Error\RuntimeError;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Webman\App;
|
||||
use Webman\Config;
|
||||
use Webman\Route;
|
||||
use Workerman\Protocols\Http\Session;
|
||||
use Workerman\Worker;
|
||||
|
||||
/**
|
||||
* Get the base path of the application
|
||||
*/
|
||||
if (!defined('BASE_PATH')) {
|
||||
if (!$basePath = Phar::running()) {
|
||||
$basePath = getcwd();
|
||||
while ($basePath !== dirname($basePath)) {
|
||||
if (is_dir("$basePath/vendor") && is_file("$basePath/start.php")) {
|
||||
break;
|
||||
}
|
||||
$basePath = dirname($basePath);
|
||||
}
|
||||
if ($basePath === dirname($basePath)) {
|
||||
$basePath = __DIR__ . '/../../../../../';
|
||||
}
|
||||
}
|
||||
define('BASE_PATH', realpath($basePath) ?: $basePath);
|
||||
}
|
||||
|
||||
if (!function_exists('run_path')) {
|
||||
/**
|
||||
* return the program execute directory
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function run_path(string $path = ''): string
|
||||
{
|
||||
static $runPath = '';
|
||||
if (!$runPath) {
|
||||
$runPath = is_phar() ? dirname(Phar::running(false)) : BASE_PATH;
|
||||
}
|
||||
return path_combine($runPath, $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('base_path')) {
|
||||
/**
|
||||
* if the param $path equal false,will return this program current execute directory
|
||||
* @param string|false $path
|
||||
* @return string
|
||||
*/
|
||||
function base_path($path = ''): string
|
||||
{
|
||||
if (false === $path) {
|
||||
return run_path();
|
||||
}
|
||||
return path_combine(BASE_PATH, $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('app_path')) {
|
||||
/**
|
||||
* App path
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function app_path(string $path = ''): string
|
||||
{
|
||||
return path_combine(BASE_PATH . DIRECTORY_SEPARATOR . 'app', $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('public_path')) {
|
||||
/**
|
||||
* Public path
|
||||
* @param string $path
|
||||
* @param string|null $plugin
|
||||
* @return string
|
||||
*/
|
||||
function public_path(string $path = '', ?string $plugin = null): string
|
||||
{
|
||||
static $publicPaths = [];
|
||||
$plugin = $plugin ?? '';
|
||||
if (isset($publicPaths[$plugin])) {
|
||||
$publicPath = $publicPaths[$plugin];
|
||||
} else {
|
||||
$prefix = $plugin ? "plugin.$plugin." : '';
|
||||
$pathPrefix = $plugin ? 'plugin' . DIRECTORY_SEPARATOR . $plugin . DIRECTORY_SEPARATOR : '';
|
||||
$publicPath = \config("{$prefix}app.public_path", run_path("{$pathPrefix}public"));
|
||||
if (count($publicPaths) > 32) {
|
||||
$publicPaths = [];
|
||||
}
|
||||
$publicPaths[$plugin] = $publicPath;
|
||||
}
|
||||
return $path === '' ? $publicPath : path_combine($publicPath, $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('config_path')) {
|
||||
/**
|
||||
* Config path
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function config_path(string $path = ''): string
|
||||
{
|
||||
return path_combine(BASE_PATH . DIRECTORY_SEPARATOR . 'config', $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('runtime_path')) {
|
||||
/**
|
||||
* Runtime path
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function runtime_path(string $path = ''): string
|
||||
{
|
||||
static $runtimePath = '';
|
||||
if (!$runtimePath) {
|
||||
$runtimePath = \config('app.runtime_path') ?: run_path('runtime');
|
||||
}
|
||||
return path_combine($runtimePath, $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('path_combine')) {
|
||||
/**
|
||||
* Generate paths based on given information
|
||||
* @param string $front
|
||||
* @param string $back
|
||||
* @return string
|
||||
*/
|
||||
function path_combine(string $front, string $back): string
|
||||
{
|
||||
return $front . ($back ? (DIRECTORY_SEPARATOR . ltrim($back, DIRECTORY_SEPARATOR)) : $back);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('response')) {
|
||||
/**
|
||||
* Response
|
||||
* @param int $status
|
||||
* @param array $headers
|
||||
* @param string $body
|
||||
* @return Response
|
||||
*/
|
||||
function response(string $body = '', int $status = 200, array $headers = []): Response
|
||||
{
|
||||
return new Response($status, $headers, $body);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('json')) {
|
||||
/**
|
||||
* Json response
|
||||
* @param $data
|
||||
* @param int $options
|
||||
* @return Response
|
||||
*/
|
||||
function json($data, int $options = JSON_UNESCAPED_UNICODE): Response
|
||||
{
|
||||
return new Response(200, ['Content-Type' => 'application/json'], json_encode($data, $options));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('xml')) {
|
||||
/**
|
||||
* Xml response
|
||||
* @param $xml
|
||||
* @return Response
|
||||
*/
|
||||
function xml($xml): Response
|
||||
{
|
||||
if ($xml instanceof SimpleXMLElement) {
|
||||
$xml = $xml->asXML();
|
||||
}
|
||||
return new Response(200, ['Content-Type' => 'text/xml'], $xml);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('jsonp')) {
|
||||
/**
|
||||
* Jsonp response
|
||||
* @param $data
|
||||
* @param string $callbackName
|
||||
* @return Response
|
||||
*/
|
||||
function jsonp($data, string $callbackName = 'callback'): Response
|
||||
{
|
||||
if (!is_scalar($data) && null !== $data) {
|
||||
$data = json_encode($data);
|
||||
}
|
||||
return new Response(200, [], "$callbackName($data)");
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('redirect')) {
|
||||
/**
|
||||
* Redirect response
|
||||
* @param string $location
|
||||
* @param int $status
|
||||
* @param array $headers
|
||||
* @return Response
|
||||
*/
|
||||
function redirect(string $location, int $status = 302, array $headers = []): Response
|
||||
{
|
||||
$response = new Response($status, ['Location' => $location]);
|
||||
if (!empty($headers)) {
|
||||
$response->withHeaders($headers);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('view')) {
|
||||
/**
|
||||
* View response
|
||||
* @param mixed $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @param string|null $plugin
|
||||
* @return Response
|
||||
*/
|
||||
function view(mixed $template = null, array $vars = [], ?string $app = null, ?string $plugin = null): Response
|
||||
{
|
||||
[$template, $vars, $app, $plugin] = template_inputs($template, $vars, $app, $plugin);
|
||||
$handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
|
||||
return new Response(200, [], $handler::render($template, $vars, $app, $plugin));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('raw_view')) {
|
||||
/**
|
||||
* Raw view response
|
||||
* @param mixed $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @param string|null $plugin
|
||||
* @return Response
|
||||
* @throws Throwable
|
||||
*/
|
||||
function raw_view(mixed $template = null, array $vars = [], ?string $app = null, ?string $plugin = null): Response
|
||||
{
|
||||
return new Response(200, [], Raw::render(...template_inputs($template, $vars, $app, $plugin)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('blade_view')) {
|
||||
/**
|
||||
* Blade view response
|
||||
* @param mixed $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @param string|null $plugin
|
||||
* @return Response
|
||||
*/
|
||||
function blade_view(mixed $template = null, array $vars = [], ?string $app = null, ?string $plugin = null): Response
|
||||
{
|
||||
return new Response(200, [], Blade::render(...template_inputs($template, $vars, $app, $plugin)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('think_view')) {
|
||||
/**
|
||||
* Think view response
|
||||
* @param mixed $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @param string|null $plugin
|
||||
* @return Response
|
||||
*/
|
||||
function think_view(mixed $template = null, array $vars = [], ?string $app = null, ?string $plugin = null): Response
|
||||
{
|
||||
return new Response(200, [], ThinkPHP::render(...template_inputs($template, $vars, $app, $plugin)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('twig_view')) {
|
||||
/**
|
||||
* Twig view response
|
||||
* @param mixed $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @param string|null $plugin
|
||||
* @return Response
|
||||
*/
|
||||
function twig_view(mixed $template = null, array $vars = [], ?string $app = null, ?string $plugin = null): Response
|
||||
{
|
||||
return new Response(200, [], Twig::render(...template_inputs($template, $vars, $app, $plugin)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('request')) {
|
||||
/**
|
||||
* Get request
|
||||
* @return \Webman\Http\Request|Request|null
|
||||
*/
|
||||
function request()
|
||||
{
|
||||
return App::request();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('config')) {
|
||||
/**
|
||||
* Get config
|
||||
* @param string|null $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
function config(?string $key = null, mixed $default = null)
|
||||
{
|
||||
return Config::get($key, $default);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('route')) {
|
||||
/**
|
||||
* Create url
|
||||
* @param string $name
|
||||
* @param ...$parameters
|
||||
* @return string
|
||||
*/
|
||||
function route(string $name, ...$parameters): string
|
||||
{
|
||||
$route = Route::getByName($name);
|
||||
if (!$route) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!$parameters) {
|
||||
return $route->url();
|
||||
}
|
||||
|
||||
if (is_array(current($parameters))) {
|
||||
$parameters = current($parameters);
|
||||
}
|
||||
|
||||
return $route->url($parameters);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('session')) {
|
||||
/**
|
||||
* Session
|
||||
* @param array|string|null $key
|
||||
* @param mixed $default
|
||||
* @return mixed|bool|Session
|
||||
* @throws Exception
|
||||
*/
|
||||
function session(array|string|null $key = null, mixed $default = null): mixed
|
||||
{
|
||||
$session = \request()->session();
|
||||
if (null === $key) {
|
||||
return $session;
|
||||
}
|
||||
if (is_array($key)) {
|
||||
$session->put($key);
|
||||
return null;
|
||||
}
|
||||
if (strpos($key, '.')) {
|
||||
$keyArray = explode('.', $key);
|
||||
$value = $session->all();
|
||||
foreach ($keyArray as $index) {
|
||||
if (!isset($value[$index])) {
|
||||
return $default;
|
||||
}
|
||||
$value = $value[$index];
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
return $session->get($key, $default);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('trans')) {
|
||||
/**
|
||||
* Translation
|
||||
* @param string $id
|
||||
* @param array $parameters
|
||||
* @param string|null $domain
|
||||
* @param string|null $locale
|
||||
* @return string
|
||||
*/
|
||||
function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string
|
||||
{
|
||||
$res = Translation::trans($id, $parameters, $domain, $locale);
|
||||
return $res === '' ? $id : $res;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('locale')) {
|
||||
/**
|
||||
* Locale
|
||||
* @param string|null $locale
|
||||
* @return string
|
||||
*/
|
||||
function locale(?string $locale = null): string
|
||||
{
|
||||
if (!$locale) {
|
||||
return Translation::getLocale();
|
||||
}
|
||||
Translation::setLocale($locale);
|
||||
return $locale;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('not_found')) {
|
||||
/**
|
||||
* 404 not found
|
||||
* @return Response
|
||||
*/
|
||||
function not_found(): Response
|
||||
{
|
||||
return new Response(404, [], file_get_contents(public_path() . '/404.html'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('copy_dir')) {
|
||||
/**
|
||||
* Copy dir
|
||||
* @param string $source
|
||||
* @param string $dest
|
||||
* @param bool $overwrite
|
||||
* @return void
|
||||
*/
|
||||
function copy_dir(string $source, string $dest, bool $overwrite = false)
|
||||
{
|
||||
if (is_dir($source)) {
|
||||
if (!is_dir($dest)) {
|
||||
mkdir($dest);
|
||||
}
|
||||
$files = scandir($source);
|
||||
foreach ($files as $file) {
|
||||
if ($file !== "." && $file !== "..") {
|
||||
copy_dir("$source/$file", "$dest/$file", $overwrite);
|
||||
}
|
||||
}
|
||||
} else if (file_exists($source) && ($overwrite || !file_exists($dest))) {
|
||||
copy($source, $dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('remove_dir')) {
|
||||
/**
|
||||
* Remove dir
|
||||
* @param string $dir
|
||||
* @return bool
|
||||
*/
|
||||
function remove_dir(string $dir): bool
|
||||
{
|
||||
if (is_link($dir) || is_file($dir)) {
|
||||
return unlink($dir);
|
||||
}
|
||||
$files = array_diff(scandir($dir), array('.', '..'));
|
||||
foreach ($files as $file) {
|
||||
(is_dir("$dir/$file") && !is_link($dir)) ? remove_dir("$dir/$file") : unlink("$dir/$file");
|
||||
}
|
||||
return rmdir($dir);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('worker_bind')) {
|
||||
/**
|
||||
* Bind worker
|
||||
* @param $worker
|
||||
* @param $class
|
||||
*/
|
||||
function worker_bind($worker, $class)
|
||||
{
|
||||
$callbackMap = [
|
||||
'onConnect',
|
||||
'onMessage',
|
||||
'onClose',
|
||||
'onError',
|
||||
'onBufferFull',
|
||||
'onBufferDrain',
|
||||
'onWorkerStop',
|
||||
'onWebSocketConnect',
|
||||
'onWorkerReload'
|
||||
];
|
||||
foreach ($callbackMap as $name) {
|
||||
if (method_exists($class, $name)) {
|
||||
$worker->$name = [$class, $name];
|
||||
}
|
||||
}
|
||||
if (method_exists($class, 'onWorkerStart')) {
|
||||
call_user_func([$class, 'onWorkerStart'], $worker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('worker_start')) {
|
||||
/**
|
||||
* Start worker
|
||||
* @param $processName
|
||||
* @param $config
|
||||
* @return void
|
||||
*/
|
||||
function worker_start($processName, $config)
|
||||
{
|
||||
if (isset($config['enable']) && !$config['enable']) {
|
||||
return;
|
||||
}
|
||||
// feat:custom worker class [default: Workerman\Worker]
|
||||
$class = is_a($class = $config['workerClass'] ?? '', Worker::class, true) ? $class : Worker::class;
|
||||
$worker = new $class($config['listen'] ?? null, $config['context'] ?? []);
|
||||
$properties = [
|
||||
'count',
|
||||
'user',
|
||||
'group',
|
||||
'reloadable',
|
||||
'reusePort',
|
||||
'transport',
|
||||
'protocol',
|
||||
'eventLoop',
|
||||
];
|
||||
$worker->name = $processName;
|
||||
foreach ($properties as $property) {
|
||||
if (isset($config[$property])) {
|
||||
$worker->$property = $config[$property];
|
||||
}
|
||||
}
|
||||
|
||||
$worker->onWorkerStart = function ($worker) use ($config) {
|
||||
require_once base_path('/support/bootstrap.php');
|
||||
if (isset($config['handler'])) {
|
||||
if (!class_exists($config['handler'])) {
|
||||
echo "process error: class {$config['handler']} not exists\r\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$instance = Container::make($config['handler'], $config['constructor'] ?? []);
|
||||
worker_bind($worker, $instance);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_realpath')) {
|
||||
/**
|
||||
* Get realpath
|
||||
* @param string $filePath
|
||||
* @return string
|
||||
*/
|
||||
function get_realpath(string $filePath): string
|
||||
{
|
||||
if (strpos($filePath, 'phar://') === 0) {
|
||||
return $filePath;
|
||||
} else {
|
||||
return realpath($filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('is_phar')) {
|
||||
/**
|
||||
* Is phar
|
||||
* @return bool
|
||||
*/
|
||||
function is_phar(): bool
|
||||
{
|
||||
return class_exists(Phar::class, false) && Phar::running();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('template_inputs')) {
|
||||
/**
|
||||
* Get template vars
|
||||
* @param mixed $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @param string|null $plugin
|
||||
* @return array
|
||||
*/
|
||||
function template_inputs(mixed $template, array $vars, ?string $app, ?string $plugin): array
|
||||
{
|
||||
$request = \request();
|
||||
$plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
|
||||
if (is_array($template)) {
|
||||
$vars = $template;
|
||||
$template = null;
|
||||
}
|
||||
if ($template === null && $controller = $request->controller) {
|
||||
$controllerSuffix = config($plugin ? "plugin.$plugin.app.controller_suffix" : "app.controller_suffix", '');
|
||||
$controllerName = $controllerSuffix !== '' ? substr($controller, 0, -strlen($controllerSuffix)) : $controller;
|
||||
$path = str_replace(['controller', 'Controller', '\\'], ['view', 'view', '/'], $controllerName);
|
||||
$path = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $path));
|
||||
$action = $request->action;
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
foreach ($backtrace as $backtraceItem) {
|
||||
if (!isset($backtraceItem['class']) || !isset($backtraceItem['function'])) {
|
||||
continue;
|
||||
}
|
||||
if ($backtraceItem['class'] === App::class) {
|
||||
break;
|
||||
}
|
||||
if (preg_match('/\\\\controller\\\\/i', $backtraceItem['class'])) {
|
||||
$action = $backtraceItem['function'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
$actionFileBaseName = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $action));
|
||||
$template = "/$path/$actionFileBaseName";
|
||||
}
|
||||
return [$template, $vars, $app, $plugin];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('cpu_count')) {
|
||||
/**
|
||||
* Get cpu count
|
||||
* @return int
|
||||
*/
|
||||
function cpu_count(): int
|
||||
{
|
||||
// Windows does not support the number of processes setting.
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
return 1;
|
||||
}
|
||||
$count = 4;
|
||||
if (is_callable('shell_exec')) {
|
||||
if (strtolower(PHP_OS) === 'darwin') {
|
||||
$count = (int)shell_exec('sysctl -n machdep.cpu.core_count');
|
||||
} else {
|
||||
try {
|
||||
$count = (int)shell_exec('nproc');
|
||||
} catch (\Throwable $ex) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
return $count > 0 ? $count : 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('input')) {
|
||||
/**
|
||||
* Get request parameters, if no parameter name is passed, an array of all values is returned, default values is supported
|
||||
* @param string|null $param param's name
|
||||
* @param mixed $default default value
|
||||
* @return mixed
|
||||
*/
|
||||
function input(?string $param = null, mixed $default = null): mixed
|
||||
{
|
||||
return is_null($param) ? request()->all() : request()->input($param, $default);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('enum_exists')) {
|
||||
/**
|
||||
* Enum exists.
|
||||
* @return bool
|
||||
*/
|
||||
function enum_exists(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?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;
|
||||
use function app_path;
|
||||
use function array_merge;
|
||||
use function base_path;
|
||||
use function config;
|
||||
use function is_array;
|
||||
use function request;
|
||||
use function runtime_path;
|
||||
|
||||
/**
|
||||
* Class Blade
|
||||
* composer require jenssegers/blade
|
||||
* @package support\view
|
||||
*/
|
||||
class Blade implements View
|
||||
{
|
||||
/**
|
||||
* Assign.
|
||||
* @param string|array $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function assign(string|array $name, mixed $value = null): void
|
||||
{
|
||||
$request = request();
|
||||
$request->_view_vars = array_merge((array) $request->_view_vars, is_array($name) ? $name : [$name => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
* @param string $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @param string|null $plugin
|
||||
* @return string
|
||||
*/
|
||||
public static function render(string $template, array $vars, ?string $app = null, ?string $plugin = null): string
|
||||
{
|
||||
static $views = [];
|
||||
$request = request();
|
||||
$plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
|
||||
$app = $app === null ? ($request->app ?? '') : $app;
|
||||
$configPrefix = $plugin ? "plugin.$plugin." : '';
|
||||
$baseViewPath = $plugin ? base_path() . "/plugin/$plugin/app" : app_path();
|
||||
if ($template[0] === '/') {
|
||||
if (strpos($template, '/view/') !== false) {
|
||||
[$viewPath, $template] = explode('/view/', $template, 2);
|
||||
$viewPath = base_path("$viewPath/view");
|
||||
} else {
|
||||
$viewPath = base_path();
|
||||
$template = ltrim($template, '/');
|
||||
}
|
||||
} else {
|
||||
$viewPath = $app === '' ? "$baseViewPath/view" : "$baseViewPath/$app/view";
|
||||
}
|
||||
if (!isset($views[$viewPath])) {
|
||||
$views[$viewPath] = new BladeView($viewPath, runtime_path() . '/views');
|
||||
$extension = config("{$configPrefix}view.extension");
|
||||
if ($extension) {
|
||||
$extension($views[$viewPath]);
|
||||
}
|
||||
}
|
||||
if(isset($request->_view_vars)) {
|
||||
$vars = array_merge((array)$request->_view_vars, $vars);
|
||||
}
|
||||
return $views[$viewPath]->render($template, $vars);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?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 Throwable;
|
||||
use Webman\View;
|
||||
use function app_path;
|
||||
use function array_merge;
|
||||
use function base_path;
|
||||
use function config;
|
||||
use function extract;
|
||||
use function is_array;
|
||||
use function ob_end_clean;
|
||||
use function ob_get_clean;
|
||||
use function ob_start;
|
||||
use function request;
|
||||
|
||||
/**
|
||||
* Class Raw
|
||||
* @package support\view
|
||||
*/
|
||||
class Raw implements View
|
||||
{
|
||||
/**
|
||||
* Assign.
|
||||
* @param string|array $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function assign(string|array $name, mixed $value = null): void
|
||||
{
|
||||
$request = request();
|
||||
$request->_view_vars = array_merge((array) $request->_view_vars, is_array($name) ? $name : [$name => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
* @param string $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @param string|null $plugin
|
||||
* @return string
|
||||
*/
|
||||
public static function render(string $template, array $vars, ?string $app = null, ?string $plugin = null): string
|
||||
{
|
||||
$request = request();
|
||||
$plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
|
||||
$configPrefix = $plugin ? "plugin.$plugin." : '';
|
||||
$viewSuffix = config("{$configPrefix}view.options.view_suffix", 'html');
|
||||
$app = $app === null ? ($request->app ?? '') : $app;
|
||||
$baseViewPath = $plugin ? base_path() . "/plugin/$plugin/app" : app_path();
|
||||
$__template_path__ = $template[0] === '/' ? base_path() . "$template.$viewSuffix" : ($app === '' ? "$baseViewPath/view/$template.$viewSuffix" : "$baseViewPath/$app/view/$template.$viewSuffix");
|
||||
if(isset($request->_view_vars)) {
|
||||
extract((array)$request->_view_vars);
|
||||
}
|
||||
extract($vars);
|
||||
ob_start();
|
||||
// Try to include php file.
|
||||
try {
|
||||
include $__template_path__;
|
||||
} catch (Throwable $e) {
|
||||
ob_end_clean();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?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;
|
||||
use function app_path;
|
||||
use function array_merge;
|
||||
use function base_path;
|
||||
use function config;
|
||||
use function is_array;
|
||||
use function ob_get_clean;
|
||||
use function ob_start;
|
||||
use function request;
|
||||
use function runtime_path;
|
||||
|
||||
/**
|
||||
* Class Blade
|
||||
* @package support\view
|
||||
*/
|
||||
class ThinkPHP implements View
|
||||
{
|
||||
/**
|
||||
* Assign.
|
||||
* @param string|array $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function assign(string|array $name, mixed $value = null): void
|
||||
{
|
||||
$request = request();
|
||||
$request->_view_vars = array_merge((array) $request->_view_vars, is_array($name) ? $name : [$name => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
* @param string $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @param string|null $plugin
|
||||
* @return string
|
||||
*/
|
||||
public static function render(string $template, array $vars, ?string $app = null, ?string $plugin = null): string
|
||||
{
|
||||
$request = request();
|
||||
$plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
|
||||
$app = $app === null ? ($request->app ?? '') : $app;
|
||||
$configPrefix = $plugin ? "plugin.$plugin." : '';
|
||||
$viewSuffix = config("{$configPrefix}view.options.view_suffix", 'html');
|
||||
$baseViewPath = $plugin ? base_path() . "/plugin/$plugin/app" : app_path();
|
||||
if ($template[0] === '/') {
|
||||
if (strpos($template, '/view/') !== false) {
|
||||
[$viewPath, $template] = explode('/view/', $template, 2);
|
||||
$viewPath = base_path("$viewPath/view/");
|
||||
} else {
|
||||
$viewPath = base_path() . dirname($template) . '/';
|
||||
$template = basename($template);
|
||||
}
|
||||
} else {
|
||||
$viewPath = $app === '' ? "$baseViewPath/view/" : "$baseViewPath/$app/view/";
|
||||
}
|
||||
$defaultOptions = [
|
||||
'view_path' => $viewPath,
|
||||
'cache_path' => runtime_path() . '/views/',
|
||||
'view_suffix' => $viewSuffix
|
||||
];
|
||||
$options = array_merge($defaultOptions, config("{$configPrefix}view.options", []));
|
||||
$views = new Template($options);
|
||||
ob_start();
|
||||
if(isset($request->_view_vars)) {
|
||||
$vars = array_merge((array)$request->_view_vars, $vars);
|
||||
}
|
||||
$views->fetch($template, $vars);
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?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\Error\LoaderError;
|
||||
use Twig\Error\RuntimeError;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
use Webman\View;
|
||||
use function app_path;
|
||||
use function array_merge;
|
||||
use function base_path;
|
||||
use function config;
|
||||
use function is_array;
|
||||
use function request;
|
||||
|
||||
/**
|
||||
* Class Blade
|
||||
* @package support\view
|
||||
*/
|
||||
class Twig implements View
|
||||
{
|
||||
/**
|
||||
* Assign.
|
||||
* @param string|array $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function assign(string|array $name, mixed $value = null): void
|
||||
{
|
||||
$request = request();
|
||||
$request->_view_vars = array_merge((array) $request->_view_vars, is_array($name) ? $name : [$name => $value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
* @param string $template
|
||||
* @param array $vars
|
||||
* @param string|null $app
|
||||
* @param string|null $plugin
|
||||
* @return string
|
||||
*/
|
||||
public static function render(string $template, array $vars, ?string $app = null, ?string $plugin = null): string
|
||||
{
|
||||
static $views = [];
|
||||
$request = request();
|
||||
$plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
|
||||
$app = $app === null ? ($request->app ?? '') : $app;
|
||||
$configPrefix = $plugin ? "plugin.$plugin." : '';
|
||||
$viewSuffix = config("{$configPrefix}view.options.view_suffix", 'html');
|
||||
$baseViewPath = $plugin ? base_path() . "/plugin/$plugin/app" : app_path();
|
||||
if ($template[0] === '/') {
|
||||
$template = ltrim($template, '/');
|
||||
if (strpos($template, '/view/') !== false) {
|
||||
[$viewPath, $template] = explode('/view/', $template, 2);
|
||||
$viewPath = base_path("$viewPath/view");
|
||||
} else {
|
||||
$viewPath = base_path();
|
||||
}
|
||||
} else {
|
||||
$viewPath = $app === '' ? "$baseViewPath/view/" : "$baseViewPath/$app/view/";
|
||||
}
|
||||
if (!isset($views[$viewPath])) {
|
||||
$views[$viewPath] = new Environment(new FilesystemLoader($viewPath), config("{$configPrefix}view.options", []));
|
||||
$extension = config("{$configPrefix}view.extension");
|
||||
if ($extension) {
|
||||
$extension($views[$viewPath]);
|
||||
}
|
||||
}
|
||||
if(isset($request->_view_vars)) {
|
||||
$vars = array_merge((array)$request->_view_vars, $vars);
|
||||
}
|
||||
return $views[$viewPath]->render("$template.$viewSuffix", $vars);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user