mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-21 15:45:36 +08:00
update to build 417
This commit is contained in:
@@ -24,7 +24,7 @@ trait CQAPI
|
||||
return $this->processHttpAPI($connection, $reply, $function);
|
||||
}
|
||||
|
||||
public function processWebsocketAPI($connection, $reply, $function = false) {
|
||||
private function processWebsocketAPI($connection, $reply, $function = false) {
|
||||
$api_id = ZMAtomic::get("wait_msg_id")->add(1);
|
||||
$reply["echo"] = $api_id;
|
||||
if (server()->push($connection->getFd(), json_encode($reply))) {
|
||||
@@ -35,7 +35,7 @@ trait CQAPI
|
||||
"self_id" => $connection->getOption("connect_id"),
|
||||
"echo" => $api_id
|
||||
];
|
||||
return CoMessage::yieldByWS($obj, ["echo"], 60);
|
||||
return CoMessage::yieldByWS($obj, ["echo"], 30);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
@@ -63,7 +63,7 @@ trait CQAPI
|
||||
* @return bool
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function processHttpAPI($connection, $reply, $function = null): bool {
|
||||
private function processHttpAPI($connection, $reply, $function = null): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace ZM\Annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use ZM\Annotation\Interfaces\ErgodicAnnotation;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
@@ -17,6 +18,7 @@ use ZM\Annotation\Http\MiddlewareClass;
|
||||
use ZM\Annotation\Http\RequestMapping;
|
||||
use ZM\Annotation\Interfaces\Level;
|
||||
use ZM\Annotation\Module\Closed;
|
||||
use ZM\Exception\AnnotationException;
|
||||
use ZM\Utils\Manager\RouteManager;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
@@ -53,7 +55,7 @@ class AnnotationParser
|
||||
*/
|
||||
public function registerMods() {
|
||||
foreach ($this->path_list as $path) {
|
||||
Console::debug("parsing annotation in " . $path[0]);
|
||||
Console::debug("parsing annotation in " . $path[0].":".$path[1]);
|
||||
$all_class = ZMUtil::getClassesPsr4($path[0], $path[1]);
|
||||
$this->reader = new AnnotationReader();
|
||||
foreach ($all_class as $v) {
|
||||
@@ -107,6 +109,7 @@ class AnnotationParser
|
||||
unset($this->annotation_map[$v]);
|
||||
continue 2;
|
||||
} elseif ($vs instanceof MiddlewareClass) {
|
||||
//注册中间件本身的类,标记到 middlewares 属性中
|
||||
Console::debug("正在注册中间件 " . $reflection_class->getName());
|
||||
$rs = $this->registerMiddleware($vs, $reflection_class);
|
||||
$this->middlewares[$rs["name"]] = $rs;
|
||||
@@ -193,6 +196,12 @@ class AnnotationParser
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal 用于 level 排序
|
||||
* @param $events
|
||||
* @param string $class_name
|
||||
* @param string $prefix
|
||||
*/
|
||||
public function sortByLevel(&$events, string $class_name, $prefix = "") {
|
||||
if (is_a($class_name, Level::class, true)) {
|
||||
$class_name .= $prefix;
|
||||
@@ -203,4 +212,22 @@ class AnnotationParser
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function verifyMiddlewares() {
|
||||
if ((ZMConfig::get("global", "runtime")["middleware_error_policy"] ?? 1) === 2) {
|
||||
//我承认套三层foreach很不优雅,但是这个会很快的。
|
||||
foreach($this->middleware_map as $class => $v) {
|
||||
foreach ($v as $method => $vs) {
|
||||
foreach($vs as $mid) {
|
||||
if (!isset($this->middlewares[$mid->middleware])) {
|
||||
throw new AnnotationException("Annotation parse error: Unknown MiddlewareClass named \"{$mid->middleware}\"!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ class ModuleListCommand extends Command
|
||||
protected static $defaultName = 'module:list';
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("Build an \".phar\" file | 将项目构建一个phar包");
|
||||
$this->setHelp("此功能将会把炸毛框架的模块打包为\".phar\",供发布和执行。");
|
||||
$this->setDescription("查看所有模块信息");
|
||||
$this->setHelp("此功能将会把炸毛框架的模块列举出来。");
|
||||
// ...
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ class ModuleListCommand extends Command
|
||||
}
|
||||
|
||||
//定义常量
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
include_once DataProvider::getFrameworkRootDir() . "/src/ZM/global_defines.php";
|
||||
|
||||
Console::init(
|
||||
@@ -47,7 +48,7 @@ class ModuleListCommand extends Command
|
||||
|
||||
foreach ($list as $v) {
|
||||
echo "[" . Console::setColor($v["name"], "green") . "]" . PHP_EOL;
|
||||
$out_list = ["类型" => "source"];
|
||||
$out_list = ["类型" => "源码(source)"];
|
||||
if (isset($v["version"])) $out_list["版本"] = $v["version"];
|
||||
if (isset($v["description"])) $out_list["描述"] = $v["description"];
|
||||
$out_list["目录"] = str_replace(DataProvider::getSourceRootDir() . "/", "", $v["module-path"]);
|
||||
@@ -59,7 +60,7 @@ class ModuleListCommand extends Command
|
||||
$list = ModuleManager::getPackedModules();
|
||||
foreach ($list as $v) {
|
||||
echo "[" . Console::setColor($v["name"], "gold") . "]" . PHP_EOL;
|
||||
$out_list = ["类型" => "archive(phar)"];
|
||||
$out_list = ["类型" => "模块包(phar)"];
|
||||
if (isset($v["module-config"]["version"])) $out_list["版本"] = $v["module-config"]["version"];
|
||||
if (isset($v["module-config"]["description"])) $out_list["描述"] = $v["module-config"]["description"];
|
||||
$out_list["位置"] = str_replace(DataProvider::getSourceRootDir() . "/", "", $v["phar-path"]);
|
||||
|
||||
@@ -21,7 +21,7 @@ class ModulePackCommand extends Command
|
||||
|
||||
protected function configure() {
|
||||
$this->addArgument("module-name", InputArgument::REQUIRED);
|
||||
$this->setDescription("Build an \".phar\" file | 将项目构建一个phar包");
|
||||
$this->setDescription("将配置好的模块构建一个phar包");
|
||||
$this->setHelp("此功能将会把炸毛框架的模块打包为\".phar\",供发布和执行。");
|
||||
$this->addOption("target", "D", InputOption::VALUE_REQUIRED, "Output Directory | 指定输出目录");
|
||||
// ...
|
||||
|
||||
@@ -22,11 +22,12 @@ class ModuleUnpackCommand extends Command
|
||||
protected function configure() {
|
||||
$this->setDefinition([
|
||||
new InputArgument("module-name", InputArgument::REQUIRED),
|
||||
new InputOption("override-light-cache", null, null, "覆盖现有的LightCache项目"),
|
||||
new InputOption("override-zm-data", null, null, "覆盖现有的zm_data文件"),
|
||||
new InputOption("override-source", null, null, "覆盖现有的源码文件")
|
||||
new InputOption("overwrite-light-cache", null, null, "覆盖现有的LightCache项目"),
|
||||
new InputOption("overwrite-zm-data", null, null, "覆盖现有的zm_data文件"),
|
||||
new InputOption("overwrite-source", null, null, "覆盖现有的源码文件"),
|
||||
new InputOption("ignore-depends", null, null, "解包时忽略检查依赖")
|
||||
]);
|
||||
$this->setDescription("Unpack a phar module into src directory");
|
||||
$this->setDescription("解包一个phar模块到src目录");
|
||||
$this->setHelp("此功能将phar格式的模块包解包到src目录下。");
|
||||
// ...
|
||||
}
|
||||
@@ -39,6 +40,7 @@ class ModuleUnpackCommand extends Command
|
||||
}
|
||||
|
||||
//定义常量
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
include_once DataProvider::getFrameworkRootDir()."/src/ZM/global_defines.php";
|
||||
|
||||
Console::init(
|
||||
|
||||
@@ -28,8 +28,8 @@ class ConsoleApplication extends Application
|
||||
{
|
||||
private static $obj = null;
|
||||
|
||||
const VERSION_ID = 416;
|
||||
const VERSION = "2.5.1";
|
||||
const VERSION_ID = 417;
|
||||
const VERSION = "2.5.2";
|
||||
|
||||
/**
|
||||
* @throws InitException
|
||||
@@ -43,6 +43,8 @@ class ConsoleApplication extends Application
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $with_default_cmd
|
||||
* @return ConsoleApplication
|
||||
* @throws InitException
|
||||
*/
|
||||
public function initEnv($with_default_cmd = ""): ConsoleApplication {
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
namespace ZM\DB;
|
||||
|
||||
|
||||
use Exception;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use ZM\MySQL\MySQLManager;
|
||||
use ZM\Store\MySQL\SqlPoolStorage;
|
||||
use PDOException;
|
||||
use PDOStatement;
|
||||
@@ -25,12 +24,12 @@ class DB
|
||||
private static $table_list = [];
|
||||
|
||||
/**
|
||||
* @param $db_name
|
||||
* @throws DbException
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function initTableList() {
|
||||
if (!extension_loaded("mysqlnd")) throw new Exception("Can not find mysqlnd PHP extension.");
|
||||
$result = self::rawQuery("select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='" . ZMConfig::get("global", "sql_config")["sql_database"] . "';", []);
|
||||
public static function initTableList($db_name) {
|
||||
if (!extension_loaded("mysqlnd")) throw new DbException("Can not find mysqlnd PHP extension.");
|
||||
$result = MySQLManager::getWrapper()->fetchAllAssociative("select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA=?;", [$db_name]);
|
||||
foreach ($result as $v) {
|
||||
self::$table_list[] = $v['TABLE_NAME'];
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
namespace ZM\Event;
|
||||
|
||||
|
||||
use Closure;
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use Error;
|
||||
use Exception;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Exception\InterruptException;
|
||||
use ZM\Store\LightCacheInside;
|
||||
@@ -117,7 +119,7 @@ class EventDispatcher
|
||||
public function dispatchEvent($v, $rule_func = null, ...$params) {
|
||||
$q_c = $v->class;
|
||||
$q_f = $v->method;
|
||||
if ($q_c === "" && ($q_f instanceof \Closure)) {
|
||||
if ($q_c === "" && ($q_f instanceof Closure)) {
|
||||
if ($this->log) Console::verbose("[事件分发{$this->eid}] 闭包函数的事件触发过程!");
|
||||
if ($rule_func !== null && !$rule_func($v)) {
|
||||
if ($this->log) Console::verbose("[事件分发{$this->eid}] 闭包函数下的 ruleFunc 判断为 false, 拒绝执行此方法。");
|
||||
@@ -137,11 +139,16 @@ class EventDispatcher
|
||||
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法下的 ruleFunc 为真,继续执行方法本身 ...");
|
||||
if (isset(EventManager::$middleware_map[$q_c][$q_f])) {
|
||||
$middlewares = EventManager::$middleware_map[$q_c][$q_f];
|
||||
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法还绑定了 Middleware:" . implode(", ", array_map(function($x){ return $x->middleware; }, $middlewares)));
|
||||
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法还绑定了 Middleware:" . implode(", ", array_map(function ($x) { return $x->middleware; }, $middlewares)));
|
||||
$before_result = true;
|
||||
$r = [];
|
||||
foreach ($middlewares as $k => $middleware) {
|
||||
if (!isset(EventManager::$middlewares[$middleware->middleware])) throw new AnnotationException("Annotation parse error: Unknown MiddlewareClass named \"{$middleware->middleware}\"!");
|
||||
if (!isset(EventManager::$middlewares[$middleware->middleware])) {
|
||||
if ((ZMConfig::get("global", "runtime")["middleware_error_policy"] ?? 1) == 1)
|
||||
throw new AnnotationException("Annotation parse error: Unknown MiddlewareClass named \"{$middleware->middleware}\"!");
|
||||
else
|
||||
continue;
|
||||
}
|
||||
$middleware_obj = EventManager::$middlewares[$middleware->middleware];
|
||||
$before = $middleware_obj["class"];
|
||||
//var_dump($middleware_obj);
|
||||
@@ -186,7 +193,8 @@ class EventDispatcher
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
for ($i = count($middlewares) - 1; $i >= 0; --$i) {
|
||||
$cnts = count($middlewares) - 1;
|
||||
for ($i = $cnts; $i >= 0; --$i) {
|
||||
$middleware_obj = EventManager::$middlewares[$middlewares[$i]->middleware];
|
||||
if (isset($middleware_obj["after"], $r[$i])) {
|
||||
if ($this->log) Console::verbose("[事件分发{$this->eid}] Middleware 存在后置事件,执行中 ...");
|
||||
|
||||
@@ -32,6 +32,7 @@ class EventManager
|
||||
self::$middlewares = $parser->getMiddlewares();
|
||||
self::$middleware_map = $parser->getMiddlewareMap();
|
||||
self::$req_mapping = $parser->getReqMapping();
|
||||
$parser->verifyMiddlewares();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@ use ZM\Event\EventDispatcher;
|
||||
use ZM\Event\EventManager;
|
||||
use ZM\Event\SwooleEvent;
|
||||
use ZM\Exception\DbException;
|
||||
use ZM\Exception\ZMException;
|
||||
use ZM\Exception\ZMKnownException;
|
||||
use ZM\Framework;
|
||||
use ZM\Module\QQBot;
|
||||
use ZM\MySQL\MySQLPool;
|
||||
@@ -32,6 +32,7 @@ use ZM\Store\LightCacheInside;
|
||||
use ZM\Store\MySQL\SqlPoolStorage;
|
||||
use ZM\Store\Redis\ZMRedisPool;
|
||||
use ZM\Utils\DataProvider;
|
||||
use ZM\Utils\Manager\ModuleManager;
|
||||
use ZM\Utils\SignalListener;
|
||||
|
||||
/**
|
||||
@@ -48,7 +49,6 @@ class OnWorkerStart implements SwooleEvent
|
||||
}
|
||||
unset(Context::$context[Coroutine::getCid()]);
|
||||
if ($server->taskworker === false) {
|
||||
|
||||
zm_atomic("_#worker_" . $worker_id)->set($server->worker_pid);
|
||||
if (LightCacheInside::get("wait_api", "wait_api") !== null) {
|
||||
LightCacheInside::unset("wait_api", "wait_api");
|
||||
@@ -144,14 +144,12 @@ class OnWorkerStart implements SwooleEvent
|
||||
$parser->addRegisterPath(DataProvider::getSourceRootDir() . "/" . $v . "/", trim($k, "\\"));
|
||||
}
|
||||
}
|
||||
$parser->registerMods();
|
||||
EventManager::loadEventByParser($parser); //加载事件
|
||||
|
||||
//加载自定义的全局函数
|
||||
Console::debug("Loading context class...");
|
||||
$context_class = ZMConfig::get("global", "context_class");
|
||||
if (!is_a($context_class, ContextInterface::class, true)) {
|
||||
throw new ZMException(zm_internal_errcode("E00032") . "Context class must implemented from ContextInterface!");
|
||||
throw new ZMKnownException("E00032", "Context class must implemented from ContextInterface!");
|
||||
}
|
||||
|
||||
//加载插件
|
||||
@@ -175,7 +173,21 @@ class OnWorkerStart implements SwooleEvent
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: 编写加载外部插件的方式
|
||||
// 检查是否允许热加载phar模块,允许的话将遍历phar内的文件
|
||||
$plugin_enable_hotload = ZMConfig::get("global", "module_loader")["enable_hotload"] ?? false;
|
||||
if ($plugin_enable_hotload) {
|
||||
$list = ModuleManager::getPackedModules();
|
||||
foreach($list as $k => $v) {
|
||||
if (\server()->worker_id === 0) Console::info("Loading packed module: ".$k);
|
||||
require_once $v["phar-path"];
|
||||
$func = "loader".$v["generated-id"];
|
||||
$func();
|
||||
$parser->addRegisterPath("phar://".$v["phar-path"]."/".$v["module-root-path"], $v["namespace"]);
|
||||
}
|
||||
}
|
||||
|
||||
$parser->registerMods();
|
||||
EventManager::loadEventByParser($parser); //加载事件
|
||||
}
|
||||
|
||||
private function initMySQLPool() {
|
||||
@@ -233,7 +245,7 @@ class OnWorkerStart implements SwooleEvent
|
||||
->withPassword($real_conf["password"])
|
||||
->withOptions($real_conf["options"] ?? [PDO::ATTR_STRINGIFY_FETCHES => false])
|
||||
);
|
||||
DB::initTableList();
|
||||
DB::initTableList($real_conf["dbname"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/ZM/Exception/AnnotationException.php
Normal file
10
src/ZM/Exception/AnnotationException.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Exception;
|
||||
|
||||
|
||||
class AnnotationException extends \Doctrine\Common\Annotations\AnnotationException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -6,9 +6,9 @@ namespace ZM\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class DbException extends ZMException
|
||||
class DbException extends ZMKnownException
|
||||
{
|
||||
public function __construct($message = "", $code = 0, Throwable $previous = null) {
|
||||
parent::__construct(zm_internal_errcode("E00043") . $message, $code, $previous);
|
||||
parent::__construct("E00043", $message, $code, $previous);
|
||||
}
|
||||
}
|
||||
|
||||
14
src/ZM/Exception/LightCacheException.php
Normal file
14
src/ZM/Exception/LightCacheException.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Exception;
|
||||
|
||||
|
||||
use Throwable;
|
||||
|
||||
class LightCacheException extends ZMKnownException
|
||||
{
|
||||
public function __construct($err_code, $message = "", $code = 0, Throwable $previous = null) {
|
||||
parent::__construct($err_code, $message, $code, $previous);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace ZM\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class ZMException extends Exception
|
||||
abstract class ZMException extends Exception
|
||||
{
|
||||
|
||||
}
|
||||
14
src/ZM/Exception/ZMKnownException.php
Normal file
14
src/ZM/Exception/ZMKnownException.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Exception;
|
||||
|
||||
|
||||
use Throwable;
|
||||
|
||||
class ZMKnownException extends ZMException
|
||||
{
|
||||
public function __construct($err_code, $message = "", $code = 0, Throwable $previous = null) {
|
||||
parent::__construct(zm_internal_errcode($err_code) . $message, $code, $previous);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,33 @@ use ZM\Annotation\Swoole\SwooleHandler;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Utils\Terminal;
|
||||
use ZM\Utils\ZMUtil;
|
||||
use function date_default_timezone_set, define;
|
||||
use function exec;
|
||||
use function explode;
|
||||
use function file_exists;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function get_class;
|
||||
use function get_included_files;
|
||||
use function in_array;
|
||||
use function intval;
|
||||
use function is_array;
|
||||
use function is_dir;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use function mkdir;
|
||||
use function ob_get_clean;
|
||||
use function ob_start;
|
||||
use function posix_getpid;
|
||||
use function str_pad;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
use function swoole_cpu_num;
|
||||
use function trim;
|
||||
use function uuidgen;
|
||||
use function working_dir;
|
||||
use function zm_atomic;
|
||||
use function zm_internal_errcode;
|
||||
|
||||
class Framework
|
||||
{
|
||||
@@ -305,9 +332,7 @@ class Framework
|
||||
$motd = file_get_contents(__DIR__ . "/../../config/motd.txt");
|
||||
}
|
||||
$motd = explode("\n", $motd);
|
||||
foreach ($motd as $k => $v) {
|
||||
$motd[$k] = substr($v, 0, $tty_width);
|
||||
}
|
||||
foreach ($motd as $k => $v) $motd[$k] = substr($v, 0, $tty_width);
|
||||
$motd = implode("\n", $motd);
|
||||
echo $motd;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,13 @@ class ModulePacker
|
||||
}
|
||||
|
||||
private function generatePharAutoload(): array {
|
||||
return ZMUtil::getClassesPsr4($this->module['module-path'], $this->module['namespace'], null, true);
|
||||
$pos = strpos($this->module['module-path'], DataProvider::getSourceRootDir().'/');
|
||||
if ($pos === 0) {
|
||||
$path_value = substr($this->module['module-path'], strlen(DataProvider::getSourceRootDir().'/'));
|
||||
} else {
|
||||
throw new ModulePackException(zm_internal_errcode("E99999")); //未定义的错误
|
||||
}
|
||||
return ZMUtil::getClassesPsr4($this->module['module-path'], $this->module['namespace'], null, $path_value);
|
||||
}
|
||||
|
||||
private function getComposerAutoloadItems(): array {
|
||||
|
||||
@@ -32,13 +32,14 @@ class ModuleUnpacker
|
||||
* @param bool $override_light_cache
|
||||
* @param bool $override_data_files
|
||||
* @param bool $override_source
|
||||
* @param bool $ignore_depends
|
||||
* @return array
|
||||
* @throws ModulePackException
|
||||
* @throws ZMException
|
||||
*/
|
||||
public function unpack(bool $override_light_cache = false, bool $override_data_files = false, bool $override_source = false): array {
|
||||
public function unpack(bool $override_light_cache = false, bool $override_data_files = false, bool $override_source = false, $ignore_depends = false): array {
|
||||
$this->checkConfig();
|
||||
$this->checkDepends();
|
||||
$this->checkDepends($ignore_depends);
|
||||
$this->checkLightCacheStore();
|
||||
$this->checkZMDataStore();
|
||||
|
||||
@@ -62,18 +63,19 @@ class ModuleUnpacker
|
||||
|
||||
/**
|
||||
* 检查模块依赖关系
|
||||
* @param bool $ignore_depends
|
||||
* @throws ModulePackException
|
||||
* @throws ZMException
|
||||
*/
|
||||
private function checkDepends() {
|
||||
private function checkDepends($ignore_depends = false) {
|
||||
$configured = ModuleManager::getConfiguredModules();
|
||||
$depends = $this->module_config["depends"] ?? [];
|
||||
foreach ($depends as $k => $v) {
|
||||
if (!isset($configured[$k])) {
|
||||
if (!isset($configured[$k]) && !$ignore_depends) {
|
||||
throw new ModulePackException(zm_internal_errcode("E00064") . "模块 " . $this->module_config["name"] . " 依赖的模块 $k 不存在");
|
||||
}
|
||||
$current_ver = $configured[$k]["version"] ?? "1.0";
|
||||
if (!VersionComparator::compareVersionRange($current_ver, $v)) {
|
||||
if (!VersionComparator::compareVersionRange($current_ver, $v) && !$ignore_depends) {
|
||||
throw new ModulePackException(zm_internal_errcode("E00063") . "模块 " . $this->module_config["name"] . " 依赖的模块 $k 版本依赖不符合条件(现有版本: " . $current_ver . ", 需求版本: " . $v . ")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,13 @@ class MySQLConnection implements Connection
|
||||
private $conn;
|
||||
|
||||
public function __construct() {
|
||||
Console::info("Constructing...");
|
||||
Console::debug("Constructing...");
|
||||
$this->conn = SqlPoolStorage::$sql_pool->getConnection();
|
||||
}
|
||||
|
||||
public function prepare($sql, $options = []) {
|
||||
try {
|
||||
Console::debug("Running SQL prepare: ".$sql);
|
||||
$statement = $this->conn->prepare($sql, $options);
|
||||
assert(($statement instanceof PDOStatementProxy) || ($statement instanceof PDOStatement));
|
||||
} catch (PDOException $exception) {
|
||||
@@ -51,6 +52,7 @@ class MySQLConnection implements Connection
|
||||
|
||||
public function exec($sql) {
|
||||
try {
|
||||
Console::debug("Running SQL exec: ".$sql);
|
||||
$statement = $this->conn->exec($sql);
|
||||
assert($statement !== false);
|
||||
return $statement;
|
||||
@@ -88,7 +90,7 @@ class MySQLConnection implements Connection
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
Console::info("Destructing!!!");
|
||||
Console::debug("Destructing!!!");
|
||||
SqlPoolStorage::$sql_pool->putConnection($this->conn);
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,16 @@
|
||||
namespace ZM\MySQL;
|
||||
|
||||
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver as DoctrineDriver;
|
||||
use Doctrine\DBAL\Platforms\MySqlPlatform;
|
||||
use Doctrine\DBAL\Schema\MySqlSchemaManager;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
|
||||
class MySQLDriver implements Driver
|
||||
class MySQLDriver implements DoctrineDriver
|
||||
{
|
||||
public function connect(array $params, $username = null, $password = null, array $driverOptions = []) {
|
||||
Console::info("Requiring new connection");
|
||||
Console::debug("Requiring new connection");
|
||||
return new MySQLConnection();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,17 +4,12 @@
|
||||
namespace ZM\MySQL;
|
||||
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\DBAL\Exception;
|
||||
|
||||
class MySQLManager
|
||||
{
|
||||
/**
|
||||
* @return Connection
|
||||
* @throws Exception
|
||||
* @return MySQLWrapper
|
||||
*/
|
||||
public static function getConnection() {
|
||||
return DriverManager::getConnection(["driverClass" => MySQLDriver::class]);
|
||||
public static function getWrapper(): MySQLWrapper {
|
||||
return new MySQLWrapper();
|
||||
}
|
||||
}
|
||||
@@ -34,4 +34,8 @@ class MySQLPool extends PDOPool
|
||||
$this->count--;
|
||||
parent::put($connection);
|
||||
}
|
||||
|
||||
public function getCount() {
|
||||
return $this->count;
|
||||
}
|
||||
}
|
||||
29
src/ZM/MySQL/MySQLQueryBuilder.php
Normal file
29
src/ZM/MySQL/MySQLQueryBuilder.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\MySQL;
|
||||
|
||||
|
||||
use Doctrine\DBAL\Query\QueryBuilder;
|
||||
use ZM\Exception\DbException;
|
||||
|
||||
class MySQLQueryBuilder extends QueryBuilder
|
||||
{
|
||||
private $wrapper;
|
||||
|
||||
public function __construct(MySQLWrapper $wrapper) {
|
||||
parent::__construct($wrapper->getConnection());
|
||||
$this->wrapper = $wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|MySQLStatementWrapper
|
||||
* @throws DbException
|
||||
*/
|
||||
public function execute() {
|
||||
if ($this->getType() === self::SELECT) {
|
||||
return $this->wrapper->executeQuery($this->getSQL(), $this->getParameters(), $this->getParameterTypes());
|
||||
}
|
||||
return $this->wrapper->executeStatement($this->getSQL(), $this->getParameters(), $this->getParameterTypes());
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,14 @@ class MySQLStatement implements Statement, \IteratorAggregate
|
||||
}
|
||||
|
||||
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = []) {
|
||||
return $this->statement->setFetchMode($fetchMode, $arg2, $arg3);
|
||||
if ($arg2 !== null && $arg3 !== [])
|
||||
return $this->statement->setFetchMode($fetchMode, $arg2, $arg3);
|
||||
elseif ($arg2 !== null && $arg3 === [])
|
||||
return $this->statement->setFetchMode($fetchMode, $arg2);
|
||||
elseif ($arg2 === null && $arg3 !== [])
|
||||
return $this->statement->setFetchMode($fetchMode, $arg2, $arg3);
|
||||
else
|
||||
return $this->statement->setFetchMode($fetchMode);
|
||||
}
|
||||
|
||||
public function fetch($fetchMode = PDO::FETCH_ASSOC, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) {
|
||||
|
||||
232
src/ZM/MySQL/MySQLStatementWrapper.php
Normal file
232
src/ZM/MySQL/MySQLStatementWrapper.php
Normal file
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @noinspection PhpMissingReturnTypeInspection
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
|
||||
namespace ZM\MySQL;
|
||||
|
||||
use Doctrine\DBAL\Driver\ResultStatement;
|
||||
use Doctrine\DBAL\ForwardCompatibility\Result;
|
||||
use Throwable;
|
||||
use Traversable;
|
||||
use ZM\Exception\DbException;
|
||||
|
||||
class MySQLStatementWrapper
|
||||
{
|
||||
public $stmt;
|
||||
|
||||
public function __construct(?Result $stmt) {
|
||||
$this->stmt = $stmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取结果的迭代器
|
||||
* wrapper method
|
||||
* @return ResultStatement
|
||||
*/
|
||||
public function getIterator() {
|
||||
return $this->stmt->getIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列数
|
||||
* wrapper method
|
||||
* @return int
|
||||
*/
|
||||
public function columnCount() {
|
||||
return $this->stmt->columnCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return array|false|mixed
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchNumeric() {
|
||||
try {
|
||||
return $this->stmt->fetchNumeric();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return array|false|mixed
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchAssociative() {
|
||||
try {
|
||||
return $this->stmt->fetchAssociative();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return false|mixed
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchOne() {
|
||||
try {
|
||||
return $this->stmt->fetchOne();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return array
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchAllNumeric(): array {
|
||||
try {
|
||||
return $this->stmt->fetchAllNumeric();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return array
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchAllAssociative(): array {
|
||||
try {
|
||||
return $this->stmt->fetchAllAssociative();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return array
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchAllKeyValue(): array {
|
||||
try {
|
||||
return $this->stmt->fetchAllKeyValue();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return array
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchAllAssociativeIndexed(): array {
|
||||
try {
|
||||
return $this->stmt->fetchAllAssociativeIndexed();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return array
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchFirstColumn(): array {
|
||||
try {
|
||||
return $this->stmt->fetchFirstColumn();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return Traversable
|
||||
* @throws DbException
|
||||
*/
|
||||
public function iterateNumeric(): Traversable {
|
||||
try {
|
||||
return $this->stmt->iterateNumeric();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return Traversable
|
||||
* @throws DbException
|
||||
*/
|
||||
public function iterateAssociative(): Traversable {
|
||||
try {
|
||||
return $this->stmt->iterateAssociative();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return Traversable
|
||||
* @throws DbException
|
||||
*/
|
||||
public function iterateKeyValue(): Traversable {
|
||||
try {
|
||||
return $this->stmt->iterateKeyValue();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return Traversable
|
||||
* @throws DbException
|
||||
*/
|
||||
public function iterateAssociativeIndexed(): Traversable {
|
||||
try {
|
||||
return $this->stmt->iterateAssociativeIndexed();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return Traversable
|
||||
* @throws DbException
|
||||
*/
|
||||
public function iterateColumn(): Traversable {
|
||||
try {
|
||||
return $this->stmt->iterateColumn();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return int
|
||||
* @throws DbException
|
||||
*/
|
||||
public function rowCount() {
|
||||
try {
|
||||
return $this->stmt->rowCount();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
*/
|
||||
public function free(): void {
|
||||
$this->stmt->free();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,15 +1,575 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
|
||||
namespace ZM\MySQL;
|
||||
|
||||
use Closure;
|
||||
use Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use Throwable;
|
||||
use Traversable;
|
||||
use ZM\Exception\DbException;
|
||||
|
||||
class MySQLWrapper
|
||||
{
|
||||
public $connection;
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* MySQLWrapper constructor.
|
||||
* @throws DbException
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->connection = MySQLManager::getConnection();
|
||||
try {
|
||||
$this->connection = DriverManager::getConnection(["driverClass" => MySQLDriver::class]);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return string
|
||||
*/
|
||||
public function getDatabase(): string {
|
||||
return $this->connection->getDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return bool
|
||||
*/
|
||||
public function isAutoCommit(): bool {
|
||||
return $this->connection->isAutoCommit();
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $autoCommit
|
||||
*/
|
||||
public function setAutoCommit($autoCommit) {
|
||||
$this->connection->setAutoCommit($autoCommit);
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return array|false
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchAssociative(string $query, array $params = [], array $types = []) {
|
||||
try {
|
||||
return $this->connection->fetchAssociative($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return array|false
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchNumeric(string $query, array $params = [], array $types = []) {
|
||||
try {
|
||||
return $this->connection->fetchNumeric($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return false|mixed
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchOne(string $query, array $params = [], array $types = []): bool {
|
||||
try {
|
||||
return $this->connection->fetchOne($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return bool
|
||||
*/
|
||||
public function isTransactionActive(): bool {
|
||||
return $this->connection->isTransactionActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @param array $criteria
|
||||
* @param array $types
|
||||
* @return int
|
||||
* @throws DbException
|
||||
*/
|
||||
public function delete($table, array $criteria, array $types = []): int {
|
||||
try {
|
||||
return $this->connection->delete($table, $criteria, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $level
|
||||
* @return int
|
||||
*/
|
||||
public function setTransactionIsolation($level): int {
|
||||
return $this->connection->setTransactionIsolation($level);
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return int|null
|
||||
*/
|
||||
public function getTransactionIsolation(): ?int {
|
||||
return $this->connection->getTransactionIsolation();
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $table
|
||||
* @param array $data
|
||||
* @param array $criteria
|
||||
* @param array $types
|
||||
* @return int
|
||||
* @throws DbException
|
||||
*/
|
||||
public function update($table, array $data, array $criteria, array $types = []): int {
|
||||
try {
|
||||
return $this->connection->update($table, $data, $criteria, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $table
|
||||
* @param array $data
|
||||
* @param array $types
|
||||
* @return int
|
||||
* @throws DbException
|
||||
*/
|
||||
public function insert($table, array $data, array $types = []): int {
|
||||
try {
|
||||
return $this->connection->insert($table, $data, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $str
|
||||
* @return string
|
||||
*/
|
||||
public function quoteIdentifier($str): string {
|
||||
return $this->connection->quoteIdentifier($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $value
|
||||
* @param int $type
|
||||
* @return mixed
|
||||
*/
|
||||
public function quote($value, $type = ParameterType::STRING) {
|
||||
return $this->connection->quote($value, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return array
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchAllNumeric(string $query, array $params = [], array $types = []): array {
|
||||
try {
|
||||
return $this->connection->fetchAllNumeric($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return array
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchAllAssociative(string $query, array $params = [], array $types = []): array {
|
||||
try {
|
||||
return $this->connection->fetchAllAssociative($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return array
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchAllKeyValue(string $query, array $params = [], array $types = []): array {
|
||||
try {
|
||||
return $this->connection->fetchAllKeyValue($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return array
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchAllAssociativeIndexed(string $query, array $params = [], array $types = []): array {
|
||||
try {
|
||||
return $this->connection->fetchAllAssociativeIndexed($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return array
|
||||
* @throws DbException
|
||||
*/
|
||||
public function fetchFirstColumn(string $query, array $params = [], array $types = []): array {
|
||||
try {
|
||||
return $this->connection->fetchFirstColumn($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return Traversable
|
||||
* @throws DbException
|
||||
*/
|
||||
public function iterateNumeric(string $query, array $params = [], array $types = []): Traversable {
|
||||
try {
|
||||
return $this->connection->iterateNumeric($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return Traversable
|
||||
* @throws DbException
|
||||
*/
|
||||
public function iterateAssociative(string $query, array $params = [], array $types = []): Traversable {
|
||||
try {
|
||||
return $this->connection->iterateAssociative($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return Traversable
|
||||
* @throws DbException
|
||||
*/
|
||||
public function iterateKeyValue(string $query, array $params = [], array $types = []): Traversable {
|
||||
try {
|
||||
return $this->connection->iterateKeyValue($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return Traversable
|
||||
* @throws DbException
|
||||
*/
|
||||
public function iterateAssociativeIndexed(string $query, array $params = [], array $types = []): Traversable {
|
||||
try {
|
||||
return $this->connection->iterateAssociativeIndexed($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return Traversable
|
||||
* @throws DbException
|
||||
*/
|
||||
public function iterateColumn(string $query, array $params = [], array $types = []): Traversable {
|
||||
try {
|
||||
return $this->connection->iterateColumn($query, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $sql
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @param QueryCacheProfile|null $qcp
|
||||
* @return MySQLStatementWrapper
|
||||
* @throws DbException
|
||||
*/
|
||||
public function executeQuery($sql, array $params = [], $types = [], ?QueryCacheProfile $qcp = null): MySQLStatementWrapper {
|
||||
try {
|
||||
$query = $this->connection->executeQuery($sql, $params, $types, $qcp);
|
||||
return new MySQLStatementWrapper($query);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $sql
|
||||
* @param $params
|
||||
* @param $types
|
||||
* @param QueryCacheProfile $qcp
|
||||
* @return MySQLStatementWrapper
|
||||
* @throws DbException
|
||||
*/
|
||||
public function executeCacheQuery($sql, $params, $types, QueryCacheProfile $qcp): MySQLStatementWrapper {
|
||||
try {
|
||||
$query = $this->connection->executeCacheQuery($sql, $params, $types, $qcp);
|
||||
return new MySQLStatementWrapper($query);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $sql
|
||||
* @param array $params
|
||||
* @param array $types
|
||||
* @return int
|
||||
* @throws DbException
|
||||
*/
|
||||
public function executeStatement($sql, array $params = [], array $types = []): int {
|
||||
try {
|
||||
return $this->connection->executeStatement($sql, $params, $types);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return int
|
||||
*/
|
||||
public function getTransactionNestingLevel(): int {
|
||||
return $this->connection->getTransactionNestingLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param null $name
|
||||
* @return string
|
||||
*/
|
||||
public function lastInsertId($name = null): string {
|
||||
return $this->connection->lastInsertId($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* overwrite method to $this->connection->transactional()
|
||||
* @param Closure $func
|
||||
* @return mixed
|
||||
* @throws DbException
|
||||
*/
|
||||
public function transactional(Closure $func) {
|
||||
$this->beginTransaction();
|
||||
try {
|
||||
$res = $func($this);
|
||||
$this->commit();
|
||||
return $res;
|
||||
} catch (Throwable $e) {
|
||||
$this->rollBack();
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $nestTransactionsWithSavepoints
|
||||
* @throws DbException
|
||||
*/
|
||||
public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints) {
|
||||
try {
|
||||
$this->connection->setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return bool
|
||||
*/
|
||||
public function getNestTransactionsWithSavepoints(): bool {
|
||||
return $this->connection->getNestTransactionsWithSavepoints();
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return bool
|
||||
*/
|
||||
public function beginTransaction(): bool {
|
||||
return $this->connection->beginTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return bool
|
||||
* @throws DbException
|
||||
*/
|
||||
public function commit(): bool {
|
||||
try {
|
||||
return $this->connection->commit();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return bool
|
||||
* @throws DbException
|
||||
*/
|
||||
public function rollBack(): bool {
|
||||
try {
|
||||
return $this->connection->rollBack();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $savepoint
|
||||
* @throws DbException
|
||||
*/
|
||||
public function createSavepoint($savepoint) {
|
||||
try {
|
||||
$this->connection->createSavepoint($savepoint);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $savepoint
|
||||
* @throws DbException
|
||||
*/
|
||||
public function releaseSavepoint($savepoint) {
|
||||
try {
|
||||
$this->connection->releaseSavepoint($savepoint);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @param $savepoint
|
||||
* @throws DbException
|
||||
*/
|
||||
public function rollbackSavepoint($savepoint) {
|
||||
try {
|
||||
$this->connection->rollbackSavepoint($savepoint);
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @throws DbException
|
||||
*/
|
||||
public function setRollbackOnly() {
|
||||
try {
|
||||
$this->connection->setRollbackOnly();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper method
|
||||
* @return bool
|
||||
* @throws DbException
|
||||
*/
|
||||
public function isRollbackOnly(): bool {
|
||||
try {
|
||||
return $this->connection->isRollbackOnly();
|
||||
} catch (Throwable $e) {
|
||||
throw new DbException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* overwrite method to $this->connection->createQueryBuilder
|
||||
* @return MySQLQueryBuilder
|
||||
*/
|
||||
public function createQueryBuilder(): MySQLQueryBuilder {
|
||||
return new MySQLQueryBuilder($this);
|
||||
}
|
||||
|
||||
public function getConnection(): Connection {
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
|
||||
@@ -9,6 +9,7 @@ use Swoole\Table;
|
||||
use ZM\Annotation\Swoole\OnSave;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Event\EventDispatcher;
|
||||
use ZM\Exception\LightCacheException;
|
||||
use ZM\Exception\ZMException;
|
||||
use ZM\Framework;
|
||||
use ZM\Utils\Manager\ProcessManager;
|
||||
@@ -86,7 +87,7 @@ class LightCache
|
||||
* @throws ZMException
|
||||
*/
|
||||
public static function get(string $key) {
|
||||
if (self::$kv_table === null) throw new ZMException(zm_internal_errcode("E00048") . "not initialized LightCache");
|
||||
if (self::$kv_table === null) throw new LightCacheException("E00048", "not initialized LightCache");
|
||||
self::checkExpire($key);
|
||||
$r = self::$kv_table->get($key);
|
||||
return $r === false ? null : self::parseGet($r);
|
||||
@@ -98,7 +99,7 @@ class LightCache
|
||||
* @throws ZMException
|
||||
*/
|
||||
public static function getExpire(string $key) {
|
||||
if (self::$kv_table === null) throw new ZMException(zm_internal_errcode("E00048") . "not initialized LightCache");
|
||||
if (self::$kv_table === null) throw new LightCacheException("E00048", "not initialized LightCache");
|
||||
self::checkExpire($key);
|
||||
$r = self::$kv_table->get($key, "expire");
|
||||
return $r === false ? null : $r - time();
|
||||
@@ -111,7 +112,7 @@ class LightCache
|
||||
* @since 2.4.3
|
||||
*/
|
||||
public static function getExpireTS(string $key) {
|
||||
if (self::$kv_table === null) throw new ZMException(zm_internal_errcode("E00048") . "not initialized LightCache");
|
||||
if (self::$kv_table === null) throw new LightCacheException("E00048", "not initialized LightCache");
|
||||
self::checkExpire($key);
|
||||
$r = self::$kv_table->get($key, "expire");
|
||||
return $r === false ? null : $r;
|
||||
@@ -125,7 +126,7 @@ class LightCache
|
||||
* @throws ZMException
|
||||
*/
|
||||
public static function set(string $key, $value, int $expire = -1) {
|
||||
if (self::$kv_table === null) throw new ZMException(zm_internal_errcode("E00048") . "not initialized LightCache");
|
||||
if (self::$kv_table === null) throw new LightCacheException("E00048", "not initialized LightCache");
|
||||
if (is_array($value)) {
|
||||
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
if (strlen($value) >= self::$config["max_strlen"]) return false;
|
||||
@@ -138,7 +139,7 @@ class LightCache
|
||||
$data_type = "bool";
|
||||
$value = json_encode($value);
|
||||
} else {
|
||||
throw new ZMException(zm_internal_errcode("E00049") . "Only can set string, array and int");
|
||||
throw new LightCacheException("E00049", "Only can set string, array and int");
|
||||
}
|
||||
try {
|
||||
return self::$kv_table->set($key, [
|
||||
@@ -158,7 +159,7 @@ class LightCache
|
||||
* @throws ZMException
|
||||
*/
|
||||
public static function update(string $key, $value) {
|
||||
if (self::$kv_table === null) throw new ZMException(zm_internal_errcode("E00048") . "not initialized LightCache.");
|
||||
if (self::$kv_table === null) throw new LightCacheException("E00048", "not initialized LightCache.");
|
||||
if (is_array($value)) {
|
||||
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
if (strlen($value) >= self::$config["max_strlen"]) return false;
|
||||
@@ -168,7 +169,7 @@ class LightCache
|
||||
} elseif (is_int($value)) {
|
||||
$data_type = "int";
|
||||
} else {
|
||||
throw new ZMException(zm_internal_errcode("E00048") . "Only can set string, array and int");
|
||||
throw new LightCacheException("E00048", "Only can set string, array and int");
|
||||
}
|
||||
try {
|
||||
if (self::$kv_table->get($key) === false) return false;
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace ZM\Store;
|
||||
|
||||
use Exception;
|
||||
use Swoole\Table;
|
||||
use ZM\Exception\LightCacheException;
|
||||
use ZM\Exception\ZMException;
|
||||
|
||||
class LightCacheInside
|
||||
@@ -67,6 +68,6 @@ class LightCacheInside
|
||||
self::$kv_table[$name] = new Table($size, $conflict_proportion);
|
||||
self::$kv_table[$name]->column("value", Table::TYPE_STRING, $str_size);
|
||||
$r = self::$kv_table[$name]->create();
|
||||
if ($r === false) throw new ZMException(zm_internal_errcode("E00050") . "内存不足,创建静态表失败!");
|
||||
if ($r === false) throw new LightCacheException("E00050", "内存不足,创建静态表失败!");
|
||||
}
|
||||
}
|
||||
|
||||
0
src/ZM/Store/ZMBuf.php
Executable file → Normal file
0
src/ZM/Store/ZMBuf.php
Executable file → Normal file
@@ -4,9 +4,11 @@
|
||||
namespace ZM\Utils\Manager;
|
||||
|
||||
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Exception\ModulePackException;
|
||||
use ZM\Exception\ZMException;
|
||||
use ZM\Exception\ZMKnownException;
|
||||
use ZM\Module\ModulePacker;
|
||||
use ZM\Module\ModuleUnpacker;
|
||||
use ZM\Utils\DataProvider;
|
||||
@@ -36,12 +38,12 @@ class ModuleManager
|
||||
if ($json === null) continue;
|
||||
if (!isset($json["name"])) continue;
|
||||
if ($pathinfo["dirname"] == ".") {
|
||||
throw new ZMException(zm_internal_errcode("E00052") . "在/src/目录下不可以直接标记为模块(zm.json),因为命名空间不能为根空间!");
|
||||
throw new ZMKnownException("E00052", "在/src/目录下不可以直接标记为模块(zm.json),因为命名空间不能为根空间!");
|
||||
}
|
||||
$json["module-path"] = realpath($dir . "/" . $pathinfo["dirname"]);
|
||||
$json["namespace"] = str_replace("/", "\\", $pathinfo["dirname"]);
|
||||
if (isset($modules[$json["name"]])) {
|
||||
throw new ZMException(zm_internal_errcode("E00053") . "重名模块:" . $json["name"]);
|
||||
throw new ZMKnownException("E00053", "重名模块:" . $json["name"]);
|
||||
}
|
||||
$modules[$json["name"]] = $json;
|
||||
}
|
||||
@@ -50,7 +52,7 @@ class ModuleManager
|
||||
}
|
||||
|
||||
public static function getPackedModules(): array {
|
||||
$dir = DataProvider::getDataFolder() . "modules";
|
||||
$dir = ZMConfig::get("global", "module_loader")["load_path"] ?? (ZM_DATA . "modules");
|
||||
$ls = DataProvider::scanDirFiles($dir, true, false);
|
||||
if ($ls === false) return [];
|
||||
$modules = [];
|
||||
@@ -88,7 +90,10 @@ class ModuleManager
|
||||
public static function packModule($module): bool {
|
||||
try {
|
||||
$packer = new ModulePacker($module);
|
||||
$packer->setOutputPath(DataProvider::getDataFolder() . "output");
|
||||
if (!is_dir(DataProvider::getDataFolder())) throw new ModulePackException(zm_internal_errcode("E00070") . "zm_data dir not found!");
|
||||
$path = realpath(DataProvider::getDataFolder() . "/output");
|
||||
if ($path === false) mkdir($path = DataProvider::getDataFolder() . "/output");
|
||||
$packer->setOutputPath($path);
|
||||
$packer->setOverride();
|
||||
$packer->pack();
|
||||
return true;
|
||||
@@ -107,7 +112,7 @@ class ModuleManager
|
||||
public static function unpackModule($module, array $options = []) {
|
||||
try {
|
||||
$packer = new ModuleUnpacker($module);
|
||||
return $packer->unpack((bool)$options["override-light-cache"], (bool)$options["override-zm-data"], (bool)$options["override-source"]);
|
||||
return $packer->unpack((bool)$options["overwrite-light-cache"], (bool)$options["overwrite-zm-data"], (bool)$options["overwrite-source"], (bool)$options["ignore-depends"]);
|
||||
} catch (ZMException $e) {
|
||||
Console::error($e->getMessage());
|
||||
return false;
|
||||
|
||||
@@ -11,6 +11,17 @@ use ZM\Framework;
|
||||
use ZM\Store\Lock\SpinLock;
|
||||
use ZM\Store\ZMAtomic;
|
||||
use ZM\Store\ZMBuf;
|
||||
use function file_get_contents;
|
||||
use function get_included_files;
|
||||
use function is_callable;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function mb_substr;
|
||||
use function md5_file;
|
||||
use function pathinfo;
|
||||
use function server;
|
||||
use function str_replace;
|
||||
use function substr;
|
||||
|
||||
class ZMUtil
|
||||
{
|
||||
@@ -45,15 +56,15 @@ class ZMUtil
|
||||
* 在工作进程中返回可以通过reload重新加载的php文件列表
|
||||
* @return string[]|string[][]
|
||||
*/
|
||||
public static function getReloadableFiles() {
|
||||
return array_map(
|
||||
function ($x) {
|
||||
return str_replace(DataProvider::getSourceRootDir() . '/', '', $x);
|
||||
}, array_diff(
|
||||
get_included_files(),
|
||||
Framework::$loaded_files
|
||||
)
|
||||
);
|
||||
public static function getReloadableFiles(): array {
|
||||
$array_map = [];
|
||||
foreach (array_diff(
|
||||
get_included_files(),
|
||||
Framework::$loaded_files
|
||||
) as $key => $x) {
|
||||
$array_map[$key] = str_replace(DataProvider::getSourceRootDir() . '/', '', $x);
|
||||
}
|
||||
return $array_map;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,10 +72,10 @@ class ZMUtil
|
||||
* @param $dir
|
||||
* @param $base_namespace
|
||||
* @param null|mixed $rule
|
||||
* @param bool $return_kv
|
||||
* @param bool $return_path_value
|
||||
* @return String[]
|
||||
*/
|
||||
public static function getClassesPsr4($dir, $base_namespace, $rule = null, $return_kv = false) {
|
||||
public static function getClassesPsr4($dir, $base_namespace, $rule = null, $return_path_value = false): array {
|
||||
// 预先读取下composer的file列表
|
||||
$composer = json_decode(file_get_contents(DataProvider::getSourceRootDir() . '/composer.json'), true);
|
||||
$classes = [];
|
||||
@@ -72,7 +83,7 @@ class ZMUtil
|
||||
$files = DataProvider::scanDirFiles($dir, true, true);
|
||||
foreach ($files as $v) {
|
||||
$pathinfo = pathinfo($v);
|
||||
if ($pathinfo['extension'] == 'php') {
|
||||
if (($pathinfo['extension'] ?? '') == 'php') {
|
||||
if ($rule === null) { //规则未设置回调时候,使用默认的识别过滤规则
|
||||
if (substr(file_get_contents($dir . '/' . $v), 6, 6) == '#plain') continue;
|
||||
elseif (mb_substr($v, 0, 7) == 'global_' || mb_substr($v, 0, 7) == 'script_') continue;
|
||||
@@ -82,7 +93,7 @@ class ZMUtil
|
||||
} elseif (is_callable($rule) && !($rule($dir, $pathinfo))) continue;
|
||||
$dirname = $pathinfo['dirname'] == '.' ? '' : (str_replace('/', '\\', $pathinfo['dirname']) . '\\');
|
||||
$class_name = $base_namespace . '\\' . $dirname . $pathinfo['filename'];
|
||||
if ($return_kv) $classes[$class_name] = $v;
|
||||
if (is_string($return_path_value)) $classes[$class_name] = $return_path_value . "/" .$v;
|
||||
else $classes[] = $class_name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,5 +7,4 @@ function loader__generated_id__() {
|
||||
}
|
||||
|
||||
}
|
||||
echo "OK!\n";
|
||||
return json_decode(file_get_contents(__DIR__.'/zmplugin.json'), true) ?? ['zm_module' => false];
|
||||
Reference in New Issue
Block a user