暂存
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
<?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 (!is_phar() && 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);
|
||||
};
|
||||
}
|
||||
|
||||
$windowsWithoutServerListen = is_phar() && DIRECTORY_SEPARATOR === '\\' && empty($config['listen']);
|
||||
$process = config('process', []);
|
||||
if ($windowsWithoutServerListen && $process) {
|
||||
$processName = isset($process['webman']) ? 'webman' : key($process);
|
||||
worker_start($processName, $process[$processName]);
|
||||
} else if (DIRECTORY_SEPARATOR === '/') {
|
||||
foreach (config('process', []) as $processName => $config) {
|
||||
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) {
|
||||
worker_start("plugin.$firm.$name.$processName", $config);
|
||||
}
|
||||
}
|
||||
foreach ($projects['process'] ?? [] as $processName => $config) {
|
||||
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,47 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of webman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
namespace support;
|
||||
|
||||
use 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)
|
||||
{
|
||||
return static::instance()->{$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,143 @@
|
||||
<?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);
|
||||
$logger = new Logger($name, $handlers, $processors);
|
||||
if (method_exists($logger, 'useLoggingLoopDetection')) {
|
||||
$logger->useLoggingLoopDetection(false);
|
||||
}
|
||||
static::$instance[$name] = $logger;
|
||||
}
|
||||
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,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,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,108 @@
|
||||
<?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
|
||||
* @param array|null $config
|
||||
* @return Translator
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public static function instance(string $plugin = '', ?array $config = null): Translator
|
||||
{
|
||||
if (!isset(static::$instance[$plugin])) {
|
||||
$config = $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 = $config['loader'] ?? [
|
||||
'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)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* @deprecated Use support\annotation\route\DisableDefaultRoute instead.
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
|
||||
class DisableDefaultRoute extends \support\annotation\route\DisableDefaultRoute
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Attach middlewares to routes/controllers/functions via attributes.
|
||||
*
|
||||
* Example:
|
||||
* #[Middleware(AuthMiddleware::class, RateLimitMiddleware::class)]
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
|
||||
class Middleware
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $middlewares = [];
|
||||
|
||||
/**
|
||||
* @param mixed ...$middlewares Middleware class names.
|
||||
*/
|
||||
public function __construct(...$middlewares)
|
||||
{
|
||||
$this->middlewares = $middlewares;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to webman middleware callable format: [MiddlewareClass, 'process'].
|
||||
* @return array
|
||||
*/
|
||||
public function getMiddlewares(): array
|
||||
{
|
||||
$middlewares = [];
|
||||
foreach ($this->middlewares as $middleware) {
|
||||
$middlewares[] = [$middleware, 'process'];
|
||||
}
|
||||
return $middlewares;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Shortcut for #[Route(methods: ['GET','POST','PUT','DELETE','PATCH','HEAD','OPTIONS'], ...)].
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Any extends Route
|
||||
{
|
||||
/**
|
||||
* @param string|null $path Route path. Null means default-route method restriction only.
|
||||
* @param string|null $name Route name
|
||||
*/
|
||||
public function __construct(?string $path = null, ?string $name = null)
|
||||
{
|
||||
parent::__construct($path, ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'], $name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Shortcut for #[Route(methods: 'DELETE', ...)].
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Delete extends Route
|
||||
{
|
||||
/**
|
||||
* @param string|null $path Route path. Null means default-route method restriction only.
|
||||
* @param string|null $name Route name
|
||||
*/
|
||||
public function __construct(?string $path = null, ?string $name = null)
|
||||
{
|
||||
parent::__construct($path, 'DELETE', $name);
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Disable webman's default route mapping for a controller or action.
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
|
||||
class DisableDefaultRoute
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Shortcut for #[Route(methods: 'GET', ...)].
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Get extends Route
|
||||
{
|
||||
/**
|
||||
* @param string|null $path Route path. Null means default-route method restriction only.
|
||||
* @param string|null $name Route name
|
||||
*/
|
||||
public function __construct(?string $path = null, ?string $name = null)
|
||||
{
|
||||
parent::__construct($path, 'GET', $name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Shortcut for #[Route(methods: 'HEAD', ...)].
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Head extends Route
|
||||
{
|
||||
/**
|
||||
* @param string|null $path Route path. Null means default-route method restriction only.
|
||||
* @param string|null $name Route name
|
||||
*/
|
||||
public function __construct(?string $path = null, ?string $name = null)
|
||||
{
|
||||
parent::__construct($path, 'HEAD', $name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Shortcut for #[Route(methods: 'OPTIONS', ...)].
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Options extends Route
|
||||
{
|
||||
/**
|
||||
* @param string|null $path Route path. Null means default-route method restriction only.
|
||||
* @param string|null $name Route name
|
||||
*/
|
||||
public function __construct(?string $path = null, ?string $name = null)
|
||||
{
|
||||
parent::__construct($path, 'OPTIONS', $name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Shortcut for #[Route(methods: 'PATCH', ...)].
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Patch extends Route
|
||||
{
|
||||
/**
|
||||
* @param string|null $path Route path. Null means default-route method restriction only.
|
||||
* @param string|null $name Route name
|
||||
*/
|
||||
public function __construct(?string $path = null, ?string $name = null)
|
||||
{
|
||||
parent::__construct($path, 'PATCH', $name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Shortcut for #[Route(methods: 'POST', ...)].
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Post extends Route
|
||||
{
|
||||
/**
|
||||
* @param string|null $path Route path. Null means default-route method restriction only.
|
||||
* @param string|null $name Route name
|
||||
*/
|
||||
public function __construct(?string $path = null, ?string $name = null)
|
||||
{
|
||||
parent::__construct($path, 'POST', $name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Shortcut for #[Route(methods: 'PUT', ...)].
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Put extends Route
|
||||
{
|
||||
/**
|
||||
* @param string|null $path Route path. Null means default-route method restriction only.
|
||||
* @param string|null $name Route name
|
||||
*/
|
||||
public function __construct(?string $path = null, ?string $name = null)
|
||||
{
|
||||
parent::__construct($path, 'PUT', $name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Define an explicit route, or restrict allowed HTTP methods for default route when path is null.
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Route
|
||||
{
|
||||
/**
|
||||
* Route path. Null means "method restriction only" for default route.
|
||||
*/
|
||||
public ?string $path;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public array $methods;
|
||||
|
||||
/**
|
||||
* Route name for URL generation.
|
||||
*/
|
||||
public ?string $name;
|
||||
|
||||
/**
|
||||
* @param string|null $path Route path, must start with "/". Null means "method restriction only" for default route.
|
||||
* @param string|string[] $methods HTTP methods
|
||||
* @param string|null $name Route name
|
||||
*/
|
||||
public function __construct(?string $path = null, array|string $methods = ['GET'], ?string $name = null)
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->methods = is_array($methods) ? $methods : [$methods];
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace support\annotation\route;
|
||||
|
||||
use Attribute;
|
||||
|
||||
/**
|
||||
* Group routes by controller-level prefix.
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
class RouteGroup
|
||||
{
|
||||
/**
|
||||
* Prefix for all routes in this controller.
|
||||
*/
|
||||
public string $prefix;
|
||||
|
||||
/**
|
||||
* @param string $prefix Route group prefix, e.g. "/api/v1"
|
||||
*/
|
||||
public function __construct(string $prefix = '')
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
use Dotenv\Dotenv;
|
||||
use support\Log;
|
||||
use Webman\Bootstrap;
|
||||
use Webman\Config;
|
||||
use Webman\Middleware;
|
||||
use Webman\Route;
|
||||
use Webman\Util;
|
||||
use Workerman\Events\Select;
|
||||
use Workerman\Worker;
|
||||
|
||||
$worker = $worker ?? null;
|
||||
|
||||
if (empty(Worker::$eventLoopClass)) {
|
||||
Worker::$eventLoopClass = Select::class;
|
||||
}
|
||||
|
||||
set_error_handler(function ($level, $message, $file = '', $line = 0) {
|
||||
if (error_reporting() & $level) {
|
||||
throw new ErrorException($message, 0, $level, $file, $line);
|
||||
}
|
||||
});
|
||||
|
||||
if ($worker) {
|
||||
register_shutdown_function(function ($startTime) {
|
||||
if (time() - $startTime <= 0.1) {
|
||||
sleep(1);
|
||||
}
|
||||
}, time());
|
||||
}
|
||||
|
||||
if (class_exists('Dotenv\Dotenv') && file_exists(base_path(false) . '/.env')) {
|
||||
if (method_exists('Dotenv\Dotenv', 'createUnsafeMutable')) {
|
||||
Dotenv::createUnsafeMutable(base_path(false))->load();
|
||||
} else {
|
||||
Dotenv::createMutable(base_path(false))->load();
|
||||
}
|
||||
}
|
||||
|
||||
Config::clear();
|
||||
support\App::loadAllConfig(['route']);
|
||||
if ($timezone = config('app.default_timezone')) {
|
||||
date_default_timezone_set($timezone);
|
||||
}
|
||||
|
||||
foreach (config('autoload.files', []) as $file) {
|
||||
include_once $file;
|
||||
}
|
||||
foreach (config('plugin', []) as $firm => $projects) {
|
||||
foreach ($projects as $name => $project) {
|
||||
if (!is_array($project)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($project['autoload']['files'] ?? [] as $file) {
|
||||
include_once $file;
|
||||
}
|
||||
}
|
||||
foreach ($projects['autoload']['files'] ?? [] as $file) {
|
||||
include_once $file;
|
||||
}
|
||||
}
|
||||
|
||||
Middleware::load(config('middleware', []));
|
||||
foreach (config('plugin', []) as $firm => $projects) {
|
||||
foreach ($projects as $name => $project) {
|
||||
if (!is_array($project) || $name === 'static') {
|
||||
continue;
|
||||
}
|
||||
Middleware::load($project['middleware'] ?? []);
|
||||
}
|
||||
Middleware::load($projects['middleware'] ?? [], $firm);
|
||||
if ($staticMiddlewares = config("plugin.$firm.static.middleware")) {
|
||||
Middleware::load(['__static__' => $staticMiddlewares], $firm);
|
||||
}
|
||||
}
|
||||
Middleware::load(['__static__' => config('static.middleware', [])]);
|
||||
|
||||
foreach (config('bootstrap', []) as $className) {
|
||||
if (!class_exists($className)) {
|
||||
$log = "Warning: Class $className setting in config/bootstrap.php not found\r\n";
|
||||
echo $log;
|
||||
Log::error($log);
|
||||
continue;
|
||||
}
|
||||
/** @var Bootstrap $className */
|
||||
$className::start($worker);
|
||||
}
|
||||
|
||||
foreach (config('plugin', []) as $firm => $projects) {
|
||||
foreach ($projects as $name => $project) {
|
||||
if (!is_array($project)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($project['bootstrap'] ?? [] as $className) {
|
||||
if (!class_exists($className)) {
|
||||
$log = "Warning: Class $className setting in config/plugin/$firm/$name/bootstrap.php not found\r\n";
|
||||
echo $log;
|
||||
Log::error($log);
|
||||
continue;
|
||||
}
|
||||
/** @var Bootstrap $className */
|
||||
$className::start($worker);
|
||||
}
|
||||
}
|
||||
foreach ($projects['bootstrap'] ?? [] as $className) {
|
||||
/** @var string $className */
|
||||
if (!class_exists($className)) {
|
||||
$log = "Warning: Class $className setting in plugin/$firm/config/bootstrap.php not found\r\n";
|
||||
echo $log;
|
||||
Log::error($log);
|
||||
continue;
|
||||
}
|
||||
/** @var Bootstrap $className */
|
||||
$className::start($worker);
|
||||
}
|
||||
}
|
||||
|
||||
$directory = base_path() . '/plugin';
|
||||
$paths = [config_path()];
|
||||
foreach (Util::scanDir($directory) as $path) {
|
||||
if (is_dir($path = "$path/config")) {
|
||||
$paths[] = $path;
|
||||
}
|
||||
}
|
||||
Route::load($paths);
|
||||
|
||||
@@ -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,672 @@
|
||||
<?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 | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR): 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);
|
||||
}
|
||||
}
|
||||
@@ -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