Merge branch 'master' into story
This commit is contained in:
@@ -20,7 +20,7 @@ class entry extends baseEntry
|
||||
|
||||
if($this->app->action == 'options') throw EndResponseException::create($this->send(204));
|
||||
|
||||
if(!isset($this->app->user) or $this->app->user->account == 'guest') throw EndResponseException::create($this->sendError(401, 'Unauthorized'));
|
||||
if(!$this->loadModel('user')->isLogon()) throw EndResponseException::create($this->sendError(401, 'Unauthorized'));
|
||||
|
||||
$this->dao = $this->loadModel('common')->dao;
|
||||
}
|
||||
@@ -219,11 +219,11 @@ class baseEntry
|
||||
* Send error response
|
||||
*
|
||||
* @param int $code
|
||||
* @param string $msg
|
||||
* @param string|object $msg
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function sendError(int $code, string $msg)
|
||||
public function sendError(int $code, string|object $msg)
|
||||
{
|
||||
$response = new stdclass();
|
||||
$response->error = $msg;
|
||||
@@ -495,7 +495,10 @@ class baseEntry
|
||||
{
|
||||
foreach($data as $object) $this->formatFields($object, $fields);
|
||||
}
|
||||
$this->formatFields($data, $fields);
|
||||
else
|
||||
{
|
||||
$this->formatFields($data, $fields);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -705,7 +708,7 @@ class baseEntry
|
||||
$method = $this->app->getMethodName();
|
||||
if($module and $method and !$this->loadModel('common')->isOpenMethod($module, $method) and !commonModel::hasPriv($module, $method))
|
||||
{
|
||||
return $this->send(403, array('error' => 'Access not allowed'));
|
||||
die($this->send(403, array('error' => 'Access not allowed')));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -685,8 +685,8 @@ class baseControl
|
||||
unset($this->view->pager->lang);
|
||||
|
||||
$output['status'] = is_object($this->view) ? 'success' : 'fail';
|
||||
$output['data'] = json_encode($this->view);
|
||||
$output['md5'] = md5(json_encode($this->view));
|
||||
$output['data'] = json_encode($this->view) ? json_encode($this->view) : '';
|
||||
$output['md5'] = md5($output['data']);
|
||||
|
||||
$this->output = json_encode($output);
|
||||
}
|
||||
@@ -1006,7 +1006,8 @@ class baseControl
|
||||
* 设置 zin 渲染上下文数据。
|
||||
*/
|
||||
$context = \zin\context();
|
||||
$context->data = (array)$this->view;
|
||||
$context->control = $this;
|
||||
$context->data = (array)$this->view;
|
||||
$context->data['zinDebug'] = array();
|
||||
|
||||
if($this->config->debug && $this->config->debug >= 2 && $this->config->installed)
|
||||
@@ -1032,7 +1033,7 @@ class baseControl
|
||||
ob_start();
|
||||
include $viewFile;
|
||||
|
||||
if(!$context->rendered) \zin\render();
|
||||
if(!$context->rendered) \zin\renderPage();
|
||||
$content = ob_get_clean();
|
||||
|
||||
ob_start();
|
||||
@@ -1085,7 +1086,7 @@ class baseControl
|
||||
{
|
||||
print(urldecode(json_encode($data)));
|
||||
$response = helper::removeUTF8Bom(ob_get_clean());
|
||||
return helper::end($response);
|
||||
return print($response);
|
||||
}
|
||||
|
||||
/* Zand will use ob_get_clean() to print, so cannot clean so early. */
|
||||
|
||||
@@ -15,6 +15,26 @@ declare(strict_types=1);
|
||||
*/
|
||||
class baseHelper
|
||||
{
|
||||
/**
|
||||
* 已加载的目录.
|
||||
* The loaded directories.
|
||||
*
|
||||
* @static
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
static $loadedDirs = array();
|
||||
|
||||
/**
|
||||
* 已经包含的文件.
|
||||
* The included files.
|
||||
*
|
||||
* @static
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
static $includedFiles = array();
|
||||
|
||||
/**
|
||||
* 设置一个对象的成员变量。
|
||||
* Set the member's value of one object.
|
||||
@@ -170,7 +190,7 @@ class baseHelper
|
||||
|
||||
$sign = !str_contains($link, '?') ? "?" : "&";
|
||||
$appendString = '';
|
||||
if($onlyBody or self::inOnlyBodyMode()) $appendString = $sign . "onlybody=yes";
|
||||
if($onlyBody or (self::inOnlyBodyMode() && !self::isAjaxRequest('modal'))) $appendString = $sign . "onlybody=yes";
|
||||
if(self::isWithTID() and !str_contains($link, 'tid=')) $appendString .= empty($appendString) ? "{$sign}tid={$_GET['tid']}" : "&tid={$_GET['tid']}";
|
||||
return $link . $appendString;
|
||||
}
|
||||
@@ -212,16 +232,13 @@ class baseHelper
|
||||
static public function import($file)
|
||||
{
|
||||
$file = realpath($file);
|
||||
if($file === false || !is_file($file)) return false;
|
||||
if($file === false) return false;
|
||||
|
||||
static $includedFiles = array();
|
||||
if(!isset($includedFiles[$file]))
|
||||
{
|
||||
include $file;
|
||||
$includedFiles[$file] = true;
|
||||
return true;
|
||||
}
|
||||
if(isset(self::$includedFiles[$file])) return true;
|
||||
if(!is_file($file)) return false;
|
||||
|
||||
include $file;
|
||||
self::$includedFiles[$file] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -665,6 +682,7 @@ class baseHelper
|
||||
static public function ls($dir, $pattern = '')
|
||||
{
|
||||
if(empty($dir)) return array();
|
||||
if(isset(self::$loadedDirs[$dir][$pattern])) return self::$loadedDirs[$dir][$pattern];
|
||||
|
||||
$files = array();
|
||||
$dir = realpath($dir);
|
||||
@@ -672,7 +690,10 @@ class baseHelper
|
||||
if($dir === false) return array();
|
||||
|
||||
if(is_dir($dir)) $files = glob($dir . DIRECTORY_SEPARATOR . '*' . $pattern);
|
||||
return empty($files) ? array() : $files;
|
||||
|
||||
self::$loadedDirs[$dir][$pattern] = $files ?: array();
|
||||
|
||||
return self::$loadedDirs[$dir][$pattern];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -803,6 +824,7 @@ class baseHelper
|
||||
*/
|
||||
public static function restartSession($sessionID = '')
|
||||
{
|
||||
if(!preg_match('/^\w+$/', $sessionID)) $sessionID = '';
|
||||
if(empty($sessionID)) $sessionID = sha1((string)mt_rand(0, mt_getrandmax()));
|
||||
|
||||
session_write_close();
|
||||
|
||||
@@ -123,6 +123,15 @@ class baseModel
|
||||
*/
|
||||
public $global;
|
||||
|
||||
/**
|
||||
* $cache对象,用于访问缓存。
|
||||
* The $cache object, used to access the cache.
|
||||
*
|
||||
* @var object
|
||||
* @access public
|
||||
*/
|
||||
public $cache;
|
||||
|
||||
/**
|
||||
* 构造方法。
|
||||
* 1. 将全局变量设为model类的成员变量,方便model的派生类调用;
|
||||
@@ -151,7 +160,7 @@ class baseModel
|
||||
|
||||
$this->loadDAO();
|
||||
$this->setSuperVars();
|
||||
$this->loadCache();
|
||||
if($this->config->cache->enable) $this->loadCache();
|
||||
|
||||
/**
|
||||
* 读取当前模块的tao类。
|
||||
|
||||
@@ -287,6 +287,16 @@ class baseRouter
|
||||
*/
|
||||
static $loadedLangs = array();
|
||||
|
||||
/**
|
||||
* 已加载的目标,可能是 model,tao 或者 zen 的实例化对象。
|
||||
* Targets loaded, maybe instance of model, tao or zen.
|
||||
*
|
||||
* @static
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
static $loadedTargets = array();
|
||||
|
||||
/**
|
||||
* 全局$lang对象。
|
||||
* The global $lang object.
|
||||
@@ -469,9 +479,6 @@ class baseRouter
|
||||
*/
|
||||
public function setClient(): void
|
||||
{
|
||||
$this->setOpenApp();
|
||||
$this->setSuperVars();
|
||||
|
||||
$this->startSession();
|
||||
|
||||
if($this->config->framework->multiSite) $this->setSiteCode() && $this->loadExtraConfig();
|
||||
@@ -483,6 +490,9 @@ class baseRouter
|
||||
|
||||
if($this->config->framework->multiLanguage) $this->loadLang('common');
|
||||
if($this->config->framework->multiTheme) $this->setClientTheme();
|
||||
|
||||
$this->setOpenApp();
|
||||
$this->setSuperVars();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -863,7 +873,7 @@ class baseRouter
|
||||
$account = isset($_SESSION['user']) ? $_SESSION['user']->account : '';
|
||||
if(empty($account) and isset($_POST['account'])) $account = $_POST['account'];
|
||||
if(empty($account) and isset($_GET['account'])) $account = $_GET['account'];
|
||||
if(empty($account)) $account = $this->cookie->za;
|
||||
if(empty($account) and isset($_COOKIE['za'])) $account = $_COOKIE['za'];
|
||||
|
||||
$vision = '';
|
||||
$sql = new sql();
|
||||
@@ -1170,16 +1180,15 @@ class baseRouter
|
||||
|
||||
$this->sessionID = isset($ztSessionHandler) ? $ztSessionHandler->getSessionID() : session_id();
|
||||
|
||||
/* Keep session if 'zentaosid'(session id) in $_GET. */
|
||||
if(isset($_GET[$this->config->sessionVar]))
|
||||
{
|
||||
helper::restartSession($_GET[$this->config->sessionVar]);
|
||||
}
|
||||
elseif(isset($_SERVER['HTTP_TOKEN'])) // If request header has token, use it as session for authentication.
|
||||
if(isset($_SERVER['HTTP_TOKEN'])) // If request header has token, use it as session for authentication.
|
||||
{
|
||||
helper::restartSession($_SERVER['HTTP_TOKEN']);
|
||||
$this->sessionID = isset($ztSessionHandler) ? $ztSessionHandler->getSessionID() : session_id();
|
||||
}
|
||||
elseif(isset($_GET[$this->config->sessionVar]))
|
||||
{
|
||||
helper::restartSession($_GET[$this->config->sessionVar]);
|
||||
}
|
||||
|
||||
define('SESSION_STARTED', true);
|
||||
}
|
||||
@@ -1199,9 +1208,10 @@ class baseRouter
|
||||
$tab = '';
|
||||
|
||||
if(isset($_SERVER['HTTP_X_ZIN_APP'])) $tab = $_SERVER['HTTP_X_ZIN_APP'];
|
||||
elseif(isset($this->lang->navGroup)) $tab = zget($this->lang->navGroup, $module, 'my');
|
||||
elseif(isset($_COOKIE['tab']) && $_COOKIE['tab'] && preg_match('/^\w+$/', $_COOKIE['tab'])) $tab = $_COOKIE['tab'];
|
||||
elseif(isset($this->lang->navGroup)) $tab = zget($this->lang->navGroup, $module, 'my');
|
||||
|
||||
if(!isset($this->lang->mainNav->{$tab}) && !isset($_SERVER['HTTP_X_ZIN_APP'])) $tab = '';
|
||||
$this->tab = empty($tab) ? 'my' : $tab;
|
||||
return;
|
||||
}
|
||||
@@ -1210,6 +1220,7 @@ class baseRouter
|
||||
$this->tab = 'my';
|
||||
if(isset($this->lang->navGroup) && $module) $this->tab = zget($this->lang->navGroup, $module, 'my');
|
||||
if(isset($_COOKIE['tab']) and $_COOKIE['tab'] and preg_match('/^\w+$/', (string) $_COOKIE['tab'])) $this->tab = $_COOKIE['tab'];
|
||||
if(!isset($this->lang->mainNav->{$this->tab})) $this->tab = 'my';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1311,8 +1322,9 @@ class baseRouter
|
||||
{
|
||||
$this->clientDevice = 'desktop';
|
||||
|
||||
if($this->cookie->device == 'mobile') $this->clientDevice = 'mobile';
|
||||
if($this->cookie->device == 'desktop') $this->clientDevice = 'desktop';
|
||||
$cookieDevice = zget($_COOKIE, 'device', 'desktop');
|
||||
if($cookieDevice == 'mobile') $this->clientDevice = 'mobile';
|
||||
if($cookieDevice == 'desktop') $this->clientDevice = 'desktop';
|
||||
|
||||
if(empty($this->cookie->device) || !str_contains('mobile,desktop', (string) $this->cookie->device))
|
||||
{
|
||||
@@ -2058,7 +2070,11 @@ class baseRouter
|
||||
|
||||
$mergedTargetDir = $this->getTmpRoot() . $class . DS . $extTargetPrefix;
|
||||
$mergedTargetFile = $mergedTargetDir . $moduleName . '.php';
|
||||
if(!is_dir($mergedTargetDir)) mkdir($mergedTargetDir, 0755, true);
|
||||
if(!is_dir($mergedTargetDir))
|
||||
{
|
||||
$made = mkdir($mergedTargetDir, 0755, true);
|
||||
if(!$made && !empty($this->config->debug)) helper::end("ERROR: Can NOT create required directory '{$mergedTargetDir}', please create it manually with correct permission.");
|
||||
}
|
||||
|
||||
/* 判断生成的缓存文件是否需要更新。 Judge whether the merged target file needed update or not. */
|
||||
if(!$this->needTargetFileUpdate($mergedTargetFile, $extFiles, $hookFiles, $apiFiles, $targetExtPaths, $mainTargetFile)) return $mergedTargetFile;
|
||||
@@ -2491,8 +2507,7 @@ class baseRouter
|
||||
if(empty($moduleName)) $moduleName = $this->moduleName;
|
||||
if(empty($appName)) $appName = $this->appName;
|
||||
|
||||
global $loadedTargets;
|
||||
if(isset($loadedTargets[$class][$appName][$moduleName])) return $loadedTargets[$class][$appName][$moduleName];
|
||||
if(isset(self::$loadedTargets[$class][$appName][$moduleName])) return self::$loadedTargets[$class][$appName][$moduleName];
|
||||
|
||||
$targetFile = $this->setTargetFile($moduleName, $appName, $class);
|
||||
|
||||
@@ -2516,14 +2531,14 @@ class baseRouter
|
||||
/**
|
||||
* 因为zen继承自control,tao继承自model,构造函数里会调用loadTarget方法,赋默认值值防止递归调用。
|
||||
*/
|
||||
if($class == 'zen' || $class == 'tao') $loadedTargets[$class][$appName][$moduleName] = false;
|
||||
if($class == 'zen' || $class == 'tao') self::$loadedTargets[$class][$appName][$moduleName] = false;
|
||||
|
||||
/**
|
||||
* 初始化target 对象并返回。
|
||||
* Init the target object and return it.
|
||||
*/
|
||||
$target = new $targetClass($appName);
|
||||
$loadedTargets[$class][$appName][$moduleName] = $target;
|
||||
self::$loadedTargets[$class][$appName][$moduleName] = $target;
|
||||
return $target;
|
||||
}
|
||||
|
||||
@@ -2607,6 +2622,7 @@ class baseRouter
|
||||
/* Remove these three params. */
|
||||
unset($passedParams['onlybody']);
|
||||
unset($passedParams['tid']);
|
||||
unset($passedParams['zin']);
|
||||
unset($passedParams['HTTP_X_REQUESTED_WITH']);
|
||||
|
||||
/* Check params from URL. */
|
||||
@@ -2635,7 +2651,7 @@ class baseRouter
|
||||
{
|
||||
if($defaultItem['default'] === '_NOT_SET') $this->triggerError("The param '$key' should pass value. ", __FILE__, __LINE__, true);
|
||||
|
||||
$defaultParams[$key] = $defaultItem['default'];
|
||||
$defaultParams[$key] = helper::convertType(strip_tags((string) $defaultItem['default']), $defaultItem['type']);
|
||||
}
|
||||
$i ++;
|
||||
}
|
||||
@@ -2708,9 +2724,7 @@ class baseRouter
|
||||
$className = strtolower($className);
|
||||
|
||||
/* 搜索$coreLibRoot(Search in $coreLibRoot) */
|
||||
$classFile = $this->coreLibRoot . $className;
|
||||
if(is_dir($classFile)) $classFile .= DS . $className;
|
||||
$classFile .= '.class.php';
|
||||
$classFile = $this->coreLibRoot . $className . DS . $className . '.class.php';
|
||||
if(!helper::import($classFile)) $this->triggerError("class file $classFile not found", __FILE__, __LINE__, true);
|
||||
|
||||
/* 如果是静态调用,则返回(If static, return) */
|
||||
@@ -2774,6 +2788,10 @@ class baseRouter
|
||||
*/
|
||||
public function loadModuleConfig(string $moduleName, string $appName = '')
|
||||
{
|
||||
if(isset(self::$loadedConfigs[$moduleName])) return false;
|
||||
|
||||
self::$loadedConfigs[$moduleName] = $moduleName;
|
||||
|
||||
global $config;
|
||||
|
||||
if($config and (!isset($config->$moduleName) or !is_object($config->$moduleName))) $config->$moduleName = new stdclass();
|
||||
@@ -2786,9 +2804,9 @@ class baseRouter
|
||||
/* 加载每一个配置文件。Load every config file. */
|
||||
foreach($configFiles as $configFile)
|
||||
{
|
||||
if(in_array($configFile, self::$loadedConfigs)) continue;
|
||||
if(isset(self::$loadedConfigs[$configFile])) continue;
|
||||
if(is_string($configFile) && file_exists($configFile)) include $configFile;
|
||||
self::$loadedConfigs[] = $configFile;
|
||||
self::$loadedConfigs[$configFile] = $configFile;
|
||||
}
|
||||
|
||||
/* 加载数据库中与本模块相关的配置项。Merge from the db configs. */
|
||||
@@ -2915,30 +2933,35 @@ class baseRouter
|
||||
* 加载语言文件,返回全局$lang对象。
|
||||
* Load lang and return it as the global lang object.
|
||||
*
|
||||
* @param string $moduleName the module name
|
||||
* @param string $moduleName the module name
|
||||
* @param string $appName the app name
|
||||
* @access public
|
||||
* @return bool|object the lang object or false.
|
||||
* @return object the lang object
|
||||
*/
|
||||
public function loadLang(string $moduleName, string $appName = ''): bool|object
|
||||
public function loadLang(string $moduleName, string $appName = ''): object
|
||||
{
|
||||
/* 计算最终要加载的语言文件。 Get the lang files to be loaded. */
|
||||
$langFilesToLoad = $this->getMainAndExtFiles($moduleName, $appName, 'lang');
|
||||
if(empty($langFilesToLoad)) return false;
|
||||
|
||||
/* 加载语言文件。Load lang files. */
|
||||
global $lang;
|
||||
if(!is_object($lang)) $lang = new language();
|
||||
if(!isset($lang->$moduleName)) $lang->$moduleName = new stdclass();
|
||||
|
||||
if(isset(self::$loadedLangs[$moduleName])) return $lang;
|
||||
|
||||
self::$loadedLangs[$moduleName] = $moduleName;
|
||||
|
||||
/* 计算最终要加载的语言文件。 Get the lang files to be loaded. */
|
||||
$langFilesToLoad = $this->getMainAndExtFiles($moduleName, $appName, 'lang');
|
||||
if(empty($langFilesToLoad)) return $lang;
|
||||
|
||||
foreach($langFilesToLoad as $langFile)
|
||||
{
|
||||
if(in_array($langFile, self::$loadedLangs)) continue;
|
||||
if(isset(self::$loadedLangs[$langFile])) continue;
|
||||
include $langFile;
|
||||
self::$loadedLangs[] = $langFile;
|
||||
self::$loadedLangs[$langFile] = $langFile;
|
||||
}
|
||||
|
||||
$this->lang = $lang;
|
||||
|
||||
return $lang;
|
||||
}
|
||||
|
||||
@@ -3103,7 +3126,11 @@ class baseRouter
|
||||
* */
|
||||
if(!function_exists('error_get_last')) return;
|
||||
$error = error_get_last();
|
||||
if($error) $this->saveError($error['type'], $error['message'], $error['file'], $error['line']);
|
||||
if($error)
|
||||
{
|
||||
$this->saveError($error['type'], $error['message'], $error['file'], $error['line']);
|
||||
if(!empty($this->config->debug) && (!is_dir($this->logRoot) || !is_writable($this->logRoot))) helper::end('ERROR: ' . $error['message']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+147
-4
@@ -236,7 +236,7 @@ class control extends baseControl
|
||||
if(!class_exists($extensionClass)) return false;
|
||||
|
||||
/* 实例化扩展类。Create an instance of the extension class and return it. */
|
||||
$extensionObject = new $extensionClass;
|
||||
$extensionObject = new $extensionClass();
|
||||
if($type == 'model') $extensionClass = str_replace(ucfirst($type), '', $extensionClass);
|
||||
$this->$extensionClass = $extensionObject;
|
||||
$this->$extensionClass->view = $this->view;
|
||||
@@ -482,10 +482,149 @@ class control extends baseControl
|
||||
|
||||
$moduleName = $moduleName ?: $this->app->getModuleName();
|
||||
$methodName = $methodName ?: $this->app->getMethodName();
|
||||
$fields = $this->loadModel('flow')->printFields($moduleName, $methodName, $object, $type, $extras);
|
||||
if(!$print) return $fields;
|
||||
|
||||
echo $fields;
|
||||
$this->loadModel('flow');
|
||||
if($type == 'html')
|
||||
{
|
||||
parse_str($extras, $result);
|
||||
$html = $this->flow->buildExtendHtmlValue($object, zget($result, 'position', 'info'));
|
||||
$html .= $this->appendExtendCssAndJS($moduleName, $methodName);
|
||||
}
|
||||
else
|
||||
{
|
||||
ob_start();
|
||||
$this->flow->printFields($moduleName, $methodName, $object, $type, $extras);
|
||||
$html = ob_get_contents();
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
if(!$print) return $html;
|
||||
echo $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加工作流新增的字段,给formGridPanel组件使用。
|
||||
* append workflow fields to form.
|
||||
*
|
||||
* @param zin\fieldList $fields
|
||||
* @param string $moduleName
|
||||
* @param string $methodName
|
||||
* @access public
|
||||
* @return zin\fieldList
|
||||
*/
|
||||
public function appendExtendFields(zin\fieldList $fields, string $moduleName = '', string $methodName = ''): zin\fieldList
|
||||
{
|
||||
if($this->config->edition == 'open') return $fields;
|
||||
|
||||
$moduleName = $moduleName ? $moduleName : $this->app->getModuleName();
|
||||
$methodName = $methodName ? $moduleName : $this->app->getMethodName();
|
||||
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName);
|
||||
if(!$flow) return $fields;
|
||||
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName);
|
||||
if(!$action || $action->extensionType != 'extend') return $fields;
|
||||
|
||||
$fieldList = $this->workflowaction->getFields($flow->module, $action->action);
|
||||
return $this->loadModel('flow')->buildFormFields($fields, $fieldList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加工作流配置的js和css到页面上。
|
||||
* append workflow js and css to form.
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @param string $methodName
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function appendExtendCssAndJS(string $moduleName = '', string $methodName = ''): string
|
||||
{
|
||||
if($this->config->edition == 'open') return '';
|
||||
|
||||
$moduleName = $moduleName ? $moduleName : $this->app->getModuleName();
|
||||
$methodName = $methodName ? $methodName : $this->app->getMethodName();
|
||||
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName);
|
||||
if(!$flow) return '';
|
||||
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName);
|
||||
if(!$action || $action->extensionType != 'extend') return '';
|
||||
|
||||
$fieldList = $this->workflowaction->getFields($flow->module, !empty($action->action) ? $action->action: '');
|
||||
|
||||
$html = '';
|
||||
if(!empty($flow->css)) $html .= "<style>$flow->css</style>";
|
||||
if(!empty($action->css)) $html .= "<style>$action->css</style>";
|
||||
|
||||
$html .= $this->loadModel('flow')->getFormulaScript($moduleName, $action, $fieldList);
|
||||
if(!empty($action->linkages)) $html .= $this->flow->getLinkageScript($action, $fieldList);
|
||||
if(!empty($flow->js)) $html .= "<script>$flow->js</script>";
|
||||
if(!empty($action->js)) $html .= "<script>$action->js</script>";
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加工作流新增的字段,给非formGridPanel组件使用。
|
||||
* append workflow field to form.
|
||||
*
|
||||
* @param string $position info|basic
|
||||
* @param object $object
|
||||
* @param string $moduleName
|
||||
* @param string $methodName
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function appendExtendForm(string $position = 'info', object $object = null, string $moduleName = '', string $methodName = ''): array
|
||||
{
|
||||
if($this->config->edition == 'open') return array();
|
||||
|
||||
$moduleName = $moduleName ? $moduleName : $this->app->getModuleName();
|
||||
$methodName = $methodName ? $moduleName : $this->app->getMethodName();
|
||||
|
||||
if(!$object) $object = new stdclass();
|
||||
|
||||
$this->loadModel('flow');
|
||||
$this->loadModel('workflowfield');
|
||||
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName);
|
||||
if(!$flow) return array();
|
||||
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName);
|
||||
if(!$action || $action->extensionType != 'extend') return array();
|
||||
|
||||
$wrapControl = array('textarea', 'richtext', 'file');
|
||||
$fieldList = $this->workflowaction->getFields($flow->module, $action->action);
|
||||
$layouts = $this->loadModel('workflowlayout')->getFields($moduleName, $methodName);
|
||||
$notEmptyRule = $this->loadModel('workflowrule')->getByTypeAndRule('system', 'notempty');
|
||||
|
||||
if($layouts)
|
||||
{
|
||||
$allFields = $this->dao->select('*')->from(TABLE_WORKFLOWFIELD)->where('module')->eq($moduleName)->fetchAll('field');
|
||||
foreach($fieldList as $fieldName => $field)
|
||||
{
|
||||
if(isset($allFields[$fieldName])) $field->default = $allFields[$fieldName]->default;
|
||||
}
|
||||
|
||||
foreach($fieldList as $key => $field)
|
||||
{
|
||||
if($field->buildin || !$field->show || !isset($layouts[$field->field]) || (!empty($field->position) && $position != $field->position)) unset($fieldList[$key]);
|
||||
|
||||
if((is_numeric($field->default) || $field->default) && empty($field->defaultValue)) $field->defaultValue = $field->default;
|
||||
if(empty($object->{$field->field})) $object->{$field->field} = $field->defaultValue;
|
||||
if(in_array($field->type, $this->config->workflowfield->numberTypes)) $field = $this->workflowfield->processNumberField($field);
|
||||
|
||||
$field->required = $field->readonly || ($notEmptyRule && strpos(",$field->rules,", ",{$notEmptyRule->id},") !== false);
|
||||
$field->control = $this->flow->buildFormControl($field);
|
||||
$field->items = $field->options ? array_filter($field->options) : null;
|
||||
$field->value = !empty($object) ? zget($object, $field->field, '') : $defaultValue;
|
||||
$field->width = $field->width != 'auto' ? $field->width : 'full';
|
||||
}
|
||||
|
||||
return $fieldList;
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -512,6 +651,10 @@ class control extends baseControl
|
||||
public function printViewFile(string $viewFile): bool|string
|
||||
{
|
||||
if(!file_exists($viewFile)) return false;
|
||||
if(substr($viewFile, -4) != '.php') return false;
|
||||
if(strpos($viewFile, '..') !== false) return false;
|
||||
if(strpos($viewFile, '/view/') === false) return false;
|
||||
if(strpos($viewFile, $this->app->getModuleRoot()) !== 0 && strpos($viewFile, $this->app->getExtensionRoot()) !== 0) return false;
|
||||
|
||||
$currentPWD = getcwd();
|
||||
chdir(dirname($viewFile));
|
||||
|
||||
@@ -494,7 +494,7 @@ function initPageEntity(object $object): array
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
function initTableData(array $items, array &$fieldList, object $model = null): array
|
||||
function initTableData(array $items, array &$fieldList, object $model = null, string $moduleName = ''): array
|
||||
{
|
||||
if(!empty($_GET['orderBy']) && strpos($_GET['orderBy'], '-') !== false) list($orderField, $orderValue) = explode('_', $_GET['orderBy']);
|
||||
if(!empty($orderField) && !empty($orderValue) && !empty($fieldList[$orderField]))
|
||||
@@ -542,12 +542,14 @@ function initTableData(array $items, array &$fieldList, object $model = null): a
|
||||
foreach($items as $item)
|
||||
{
|
||||
$item->actions = array();
|
||||
|
||||
$actionList = zget($fieldList['actions'], 'list', array());
|
||||
foreach($fieldList['actions']['menu'] as $actionKey => $actionMenu)
|
||||
{
|
||||
if(isset($actionMenu['other']))
|
||||
{
|
||||
$currentActionMenu = $actionMenu[0];
|
||||
initItemActions($item, $currentActionMenu, zget($fieldList['actions'], 'list', array()), $model);
|
||||
initItemActions($item, $currentActionMenu, $actionList, $model);
|
||||
|
||||
$otherActionMenus = $actionMenu['other'];
|
||||
$otherAction = '';
|
||||
@@ -556,24 +558,26 @@ function initTableData(array $items, array &$fieldList, object $model = null): a
|
||||
$otherActions = explode('|', $otherActionMenu);
|
||||
foreach($otherActions as $otherActionName)
|
||||
{
|
||||
if(!checkOtherPriv(zget($actionList, $otherActionName, array()), $otherActionName, $item, $model)) continue;
|
||||
if(in_array($otherActionName, array_column($item->actions, 'name'))) continue;
|
||||
|
||||
if(method_exists($model, 'isClickable') && !$model->isClickable($item, $otherActionName)) $otherAction .= '-';
|
||||
$otherAction .= $otherActionName . ',';
|
||||
}
|
||||
}
|
||||
$item->actions[] = 'other:' . $otherAction;
|
||||
if($otherAction) $item->actions[] = 'other:' . $otherAction;
|
||||
}
|
||||
elseif($actionKey === 'more')
|
||||
{
|
||||
$moreAction = '';
|
||||
foreach($actionMenu as $moreActionName)
|
||||
{
|
||||
if(!checkOtherPriv(zget($actionList, $moreActionName, array()), $moreActionName, $item, $model)) continue;
|
||||
if(method_exists($model, 'isClickable') && !$model->isClickable($item, $moreActionName)) $moreAction .= '-';
|
||||
$moreAction .= $moreActionName . ',';
|
||||
}
|
||||
|
||||
$item->actions[] = 'more:' . $moreAction;
|
||||
if($moreAction) $item->actions[] = 'more:' . $moreAction;
|
||||
}
|
||||
elseif(is_array($actionMenu)) // Two or more grups.
|
||||
{
|
||||
@@ -602,6 +606,26 @@ function initTableData(array $items, array &$fieldList, object $model = null): a
|
||||
return array_values($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check other action priv.
|
||||
*
|
||||
* @param array $actionList
|
||||
* @param string $actionName
|
||||
* @param object $item
|
||||
* @param object $model
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
function checkOtherPriv(array $actionConfig, string $action, object $item, object $model)
|
||||
{
|
||||
$module = $model->getModuleName();
|
||||
if(!empty($actionConfig['url']['module']) && $module != $actionConfig['url']['module']) $module = $actionConfig['url']['module'];
|
||||
|
||||
$method = $action;
|
||||
if(!empty($actionConfig['url']['method']) && $method != $actionConfig['url']['method']) $method = $actionConfig['url']['method'];
|
||||
return common::hasPriv($module, $method, $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent property of the data.
|
||||
*
|
||||
@@ -613,10 +637,10 @@ function setParent(array $items)
|
||||
{
|
||||
foreach($items as $item)
|
||||
{
|
||||
$item->isParent = false;
|
||||
if(!isset($item->parent) || !is_int($item->parent)) continue;
|
||||
if(isset($item->isParent)) continue;
|
||||
|
||||
/* Set parent attribute. */
|
||||
$item->isParent = false;
|
||||
if(isset($item->parent) && $item->parent == -1)
|
||||
{
|
||||
/* When the parent is -1, the hierarchical structure is displayed incorrectly. */
|
||||
@@ -645,7 +669,7 @@ function initTableActions(array &$fieldList, string $actionMenu): void
|
||||
if(!isset($fieldList['actions']['list'][$action])) continue;
|
||||
|
||||
$actionConfig = $fieldList['actions']['list'][$action];
|
||||
$actionConfig['text'] = '';
|
||||
if(!empty($actionConfig['icon'])) $actionConfig['text'] = '';
|
||||
|
||||
if(!empty($actionConfig['url']['module']) && !empty($actionConfig['url']['method']))
|
||||
{
|
||||
@@ -653,7 +677,7 @@ function initTableActions(array &$fieldList, string $actionMenu): void
|
||||
$method = $actionConfig['url']['method'];
|
||||
$params = !empty($actionConfig['url']['params']) ? $actionConfig['url']['params'] : array();
|
||||
|
||||
$actionConfig['url'] = helper::createLink($module, $method, $params);
|
||||
$actionConfig['url'] = helper::createLink($module, $method, $params, '', !empty($actionConfig['url']['onlybody']));
|
||||
}
|
||||
|
||||
$fieldList['actions']['actionsMap'][$action] = $actionConfig;
|
||||
@@ -693,7 +717,11 @@ function initItemActions(object &$item, string $actionMenu, array $actionList, o
|
||||
if(!empty($actionConfig['url']['module']) && $module != $actionConfig['url']['module'])
|
||||
{
|
||||
$module = $actionConfig['url']['module'];
|
||||
if(!$notLoadModel) $model = $app->control->loadModel($module);
|
||||
if(!$notLoadModel)
|
||||
{
|
||||
$rawModule = $module == 'projectbuild' ? 'build' : $module;
|
||||
$model = $app->control->loadModel($rawModule);
|
||||
}
|
||||
}
|
||||
|
||||
$method = $action;
|
||||
@@ -741,3 +769,21 @@ function getVisions(): array
|
||||
$visionList = $lang->visionList;
|
||||
return array_intersect_key($visionList, $visions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save any message with any type to the php log file which prefix with 'php.<today>'.
|
||||
*
|
||||
* @param mixed $message
|
||||
* @param string $file
|
||||
* @param int $line
|
||||
* @return void
|
||||
*/
|
||||
function debug($message = '', $file = 'undefined', $line = 0)
|
||||
{
|
||||
if(!is_string($message)) $message = (string)json_encode($message, JSON_PRETTY_PRINT);
|
||||
|
||||
if(empty($file) || $file == 'undefined') $message .= (new Exception())->getTraceAsString();
|
||||
|
||||
global $app;
|
||||
$app->saveError(E_USER_WARNING, $message, $file, $line);
|
||||
}
|
||||
|
||||
+45
-20
@@ -122,13 +122,15 @@ class router extends baseRouter
|
||||
* @param string $moduleName the module name
|
||||
* @param string $appName the app name
|
||||
* @access public
|
||||
* @return bool|object the lang object or false.
|
||||
* @return object the lang object or false.
|
||||
*/
|
||||
public function loadLang($moduleName, $appName = ''): bool|object
|
||||
public function loadLang($moduleName, $appName = ''): object
|
||||
{
|
||||
global $lang;
|
||||
if(!is_object($lang)) $lang = new language();
|
||||
|
||||
if(isset(self::$loadedModules[$moduleName])) return $lang;
|
||||
|
||||
/* Set productCommon and projectCommon for flow. */
|
||||
if($moduleName == 'common') $this->setCommonLang();
|
||||
|
||||
@@ -298,7 +300,7 @@ class router extends baseRouter
|
||||
$config->executionLink = 'execution-task';
|
||||
|
||||
/* Get user preference. */
|
||||
$account = $this->session->user->account ?? '';
|
||||
$account = $_SESSION['user']->account ?? '';
|
||||
$userSetting = array();
|
||||
if($this->dbh and !empty($this->config->db->name) and $account)
|
||||
{
|
||||
@@ -350,20 +352,21 @@ class router extends baseRouter
|
||||
$lang->ERCommon = $ERPairs[$config->URSR] ?? reset($ERPairs);
|
||||
$lang->URCommon = $URPairs[$config->URSR] ?? reset($URPairs);
|
||||
$lang->SRCommon = $SRPairs[$config->URSR] ?? reset($SRPairs);
|
||||
}
|
||||
|
||||
/* Replace common lang. */
|
||||
$customMenus = array();
|
||||
try
|
||||
{
|
||||
$customMenus = $this->dbQuery('SELECT * FROM' . TABLE_LANG . "WHERE `module`='common' AND `lang`='{$this->clientLang}' AND `section`='' AND `vision`='{$config->vision}'")->fetchAll();
|
||||
}
|
||||
catch(PDOException){}
|
||||
foreach($customMenus as $menu)
|
||||
{
|
||||
/* Modified the language item of dev story-related navigation, which will only affect users whose personalized value is the same as the story concept default value.*/
|
||||
if(in_array($menu->key, array('ERCommon', 'URCommon', 'SRCommon')) && $URSR != $config->URSR) continue;
|
||||
if(isset($lang->{$menu->key})) $lang->{$menu->key} = $menu->value;
|
||||
/* Replace common lang. */
|
||||
$customMenus = array();
|
||||
try
|
||||
{
|
||||
$customMenus = $this->dbQuery('SELECT * FROM' . TABLE_LANG . "WHERE `module`='common' AND `lang`='{$this->clientLang}' AND `section`='' AND `vision`='{$config->vision}'")->fetchAll();
|
||||
}
|
||||
catch(PDOException){}
|
||||
|
||||
foreach($customMenus as $menu)
|
||||
{
|
||||
/* Modified the language item of dev story-related navigation, which will only affect users whose personalized value is the same as the story concept default value.*/
|
||||
if(in_array($menu->key, array('ERCommon', 'URCommon', 'SRCommon')) && $URSR != $config->URSR) continue;
|
||||
if(isset($lang->{$menu->key})) $lang->{$menu->key} = $menu->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -402,7 +405,10 @@ class router extends baseRouter
|
||||
*/
|
||||
public function loadModuleConfig($moduleName, $appName = '')
|
||||
{
|
||||
$extConfigPath = array();
|
||||
if(isset(self::$loadedConfigs[$moduleName])) return false;
|
||||
|
||||
self::$loadedConfigs[$moduleName] = $moduleName;
|
||||
|
||||
global $config;
|
||||
if($config and (!isset($config->$moduleName) or !is_object($config->$moduleName))) $config->$moduleName = new stdclass();
|
||||
|
||||
@@ -419,6 +425,7 @@ class router extends baseRouter
|
||||
$configDirFiles = helper::ls($this->getModulePath($appName, $moduleName) . DS . 'config', '.php');
|
||||
|
||||
/* 查找扩展配置文件。Get extension config files. */
|
||||
$extConfigPath = array();
|
||||
if($config->framework->extensionLevel > 0) $extConfigPath = $this->getModuleExtPath($moduleName, 'config');
|
||||
if($config->framework->extensionLevel >= 1)
|
||||
{
|
||||
@@ -437,9 +444,9 @@ class router extends baseRouter
|
||||
/* 加载每一个配置文件。Load every config file. */
|
||||
foreach($configFiles as $configFile)
|
||||
{
|
||||
if(in_array($configFile, self::$loadedConfigs)) continue;
|
||||
if(isset(self::$loadedConfigs[$configFile])) continue;
|
||||
if(file_exists($configFile)) include $configFile;
|
||||
self::$loadedConfigs[] = $configFile;
|
||||
self::$loadedConfigs[$configFile] = $configFile;
|
||||
}
|
||||
|
||||
/* 加载数据库中与本模块相关的配置项。Merge from the db configs. */
|
||||
@@ -757,8 +764,26 @@ class router extends baseRouter
|
||||
*/
|
||||
public function checkInstalled()
|
||||
{
|
||||
if(!$this->config->installed) return false;
|
||||
if(($this->config->inContainer || $this->config->inQuickon) && !$this->getInstalledVersion()) return false;
|
||||
|
||||
return isset($this->config->installed) && $this->config->installed;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取禅道版本在不同语言下的显示名称。
|
||||
* Get the display name of the ZenTaoPMS version in different language.
|
||||
*
|
||||
* @param string $version 20.0|biz9.0|max5.0|ipd2.0
|
||||
* @return string
|
||||
*/
|
||||
public function getVersionName($version = '')
|
||||
{
|
||||
global $config, $lang;
|
||||
$editionName = $config->edition === 'open' ? $lang->pmsName : $lang->{$config->edition . 'Name'};
|
||||
$versionName = empty($version) ? $config->version : $version;
|
||||
$versionName = $editionName . str_replace(array('max', 'biz', 'ipd'), '', $versionName);
|
||||
$versionName = ($config->inQuickon ? $lang->devopsPrefix : '') . $versionName;
|
||||
return $versionName;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user