mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 23:44:11 +01:00
Compare commits
23 Commits
develop
...
feature/47
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9872702f59 | ||
|
|
7e7b5874a6 | ||
|
|
11f142b782 | ||
|
|
af790269f0 | ||
|
|
86fe9d6a2b | ||
|
|
cdbe331c35 | ||
|
|
c14ac90a13 | ||
|
|
794a9afe3e | ||
|
|
a0a86782c7 | ||
|
|
ac2b787e09 | ||
|
|
1962cd7a88 | ||
|
|
f7b5091b39 | ||
|
|
a587bd68eb | ||
|
|
08c77f8106 | ||
|
|
61c2b71f1f | ||
|
|
f47309f535 | ||
|
|
79e1572c9e | ||
|
|
812e24b402 | ||
|
|
8af748bd3e | ||
|
|
788b23a485 | ||
|
|
6d80b2e5ed | ||
|
|
07d7995a51 | ||
|
|
1bc14f97e1 |
@@ -2856,20 +2856,8 @@ class Config
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($aModuleInfo['installer']))
|
||||
{
|
||||
$sModuleInstallerClass = $aModuleInfo['installer'];
|
||||
if (!class_exists($sModuleInstallerClass))
|
||||
{
|
||||
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']);
|
||||
}
|
||||
if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI'))
|
||||
{
|
||||
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']);
|
||||
}
|
||||
$aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig');
|
||||
call_user_func_array($aCallSpec, array($this));
|
||||
}
|
||||
|
||||
RunTimeEnvironment::CallInstallerHandler($aModuleInfo, "BeforeWritingConfig", [$this]);
|
||||
}
|
||||
}
|
||||
$this->SetAddOns($aAddOns);
|
||||
|
||||
@@ -14,7 +14,10 @@ if (PHP_VERSION_ID < 50600) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException($err);
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
@@ -469,6 +469,44 @@ return array(
|
||||
'Combodo\\iTop\\Form\\Validator\\NotEmptyExtKeyValidator' => $baseDir . '/sources/Form/Validator/NotEmptyExtKeyValidator.php',
|
||||
'Combodo\\iTop\\Form\\Validator\\SelectObjectValidator' => $baseDir . '/sources/Form/Validator/SelectObjectValidator.php',
|
||||
'Combodo\\iTop\\Kernel' => $baseDir . '/sources/Kernel.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\AbstractExprEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/AbstractExprEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ArrayDimFetchEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/ArrayDimFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ArrayEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/ArrayEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BinaryOpEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/BinaryOpEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BitwiseAndEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/BitwiseAndEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BitwiseNotEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/BitwiseNotEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BitwiseOrEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/BitwiseOrEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BitwiseXorEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/BitwiseXorEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BooleanAndEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/BooleanAndEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BooleanNotEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/BooleanNotEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BooleanOrEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/BooleanOrEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\CastEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/CastEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ClassConstFetchEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/ClassConstFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\CoalesceEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/CoalesceEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ConcatEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/ConcatEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ConstFetchEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/ConstFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\EqualEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/EqualEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\FuncCallEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/FuncCallEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\GreaterEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/GreaterEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\GreaterOrEqualEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/GreaterOrEqualEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\IssetEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/IssetEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\MethodCallEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/MethodCallEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ModEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/ModEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\MulEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/MulEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\NotEqualEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/NotEqualEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\NullsafeMethodCallEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/NullsafeMethodCallEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\NullsafePropertyFetchEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/NullsafePropertyFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\PropertyFetchEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/PropertyFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\SmallerEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/SmallerEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\SmallerOrEqualEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/SmallerOrEqualEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\StaticCallEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/StaticCallEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\StaticPropertyFetchEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/StaticPropertyFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\TernaryEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/TernaryEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\UnaryMinusEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/UnaryMinusEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\UnaryPlusEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/UnaryPlusEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\VariableEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/VariableEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\iExprEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/iExprEvaluator.php',
|
||||
'Combodo\\iTop\\Renderer\\BlockRenderer' => $baseDir . '/sources/Renderer/BlockRenderer.php',
|
||||
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => $baseDir . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
|
||||
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => $baseDir . '/sources/Renderer/Bootstrap/BsFormRenderer.php',
|
||||
|
||||
@@ -56,7 +56,7 @@ return array(
|
||||
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
|
||||
'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'),
|
||||
'Pelago\\Emogrifier\\' => array($vendorDir . '/pelago/emogrifier/src'),
|
||||
'League\\OAuth2\\Client\\' => array($vendorDir . '/league/oauth2-google/src', $vendorDir . '/league/oauth2-client/src'),
|
||||
'League\\OAuth2\\Client\\' => array($vendorDir . '/league/oauth2-client/src', $vendorDir . '/league/oauth2-google/src'),
|
||||
'Laminas\\Validator\\' => array($vendorDir . '/laminas/laminas-validator/src'),
|
||||
'Laminas\\Stdlib\\' => array($vendorDir . '/laminas/laminas-stdlib/src'),
|
||||
'Laminas\\ServiceManager\\' => array($vendorDir . '/laminas/laminas-servicemanager/src'),
|
||||
|
||||
@@ -317,8 +317,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
),
|
||||
'League\\OAuth2\\Client\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/league/oauth2-google/src',
|
||||
1 => __DIR__ . '/..' . '/league/oauth2-client/src',
|
||||
0 => __DIR__ . '/..' . '/league/oauth2-client/src',
|
||||
1 => __DIR__ . '/..' . '/league/oauth2-google/src',
|
||||
),
|
||||
'Laminas\\Validator\\' =>
|
||||
array (
|
||||
@@ -847,6 +847,44 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Form\\Validator\\NotEmptyExtKeyValidator' => __DIR__ . '/../..' . '/sources/Form/Validator/NotEmptyExtKeyValidator.php',
|
||||
'Combodo\\iTop\\Form\\Validator\\SelectObjectValidator' => __DIR__ . '/../..' . '/sources/Form/Validator/SelectObjectValidator.php',
|
||||
'Combodo\\iTop\\Kernel' => __DIR__ . '/../..' . '/sources/Kernel.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\AbstractExprEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/AbstractExprEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ArrayDimFetchEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/ArrayDimFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ArrayEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/ArrayEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BinaryOpEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/BinaryOpEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BitwiseAndEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/BitwiseAndEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BitwiseNotEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/BitwiseNotEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BitwiseOrEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/BitwiseOrEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BitwiseXorEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/BitwiseXorEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BooleanAndEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/BooleanAndEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BooleanNotEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/BooleanNotEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\BooleanOrEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/BooleanOrEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\CastEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/CastEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ClassConstFetchEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/ClassConstFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\CoalesceEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/CoalesceEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ConcatEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/ConcatEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ConstFetchEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/ConstFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\EqualEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/EqualEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\FuncCallEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/FuncCallEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\GreaterEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/GreaterEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\GreaterOrEqualEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/GreaterOrEqualEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\IssetEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/IssetEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\MethodCallEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/MethodCallEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\ModEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/ModEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\MulEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/MulEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\NotEqualEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/NotEqualEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\NullsafeMethodCallEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/NullsafeMethodCallEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\NullsafePropertyFetchEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/NullsafePropertyFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\PropertyFetchEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/PropertyFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\SmallerEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/SmallerEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\SmallerOrEqualEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/SmallerOrEqualEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\StaticCallEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/StaticCallEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\StaticPropertyFetchEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/StaticPropertyFetchEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\TernaryEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/TernaryEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\UnaryMinusEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/UnaryMinusEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\UnaryPlusEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/UnaryPlusEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\VariableEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/VariableEvaluator.php',
|
||||
'Combodo\\iTop\\PhpParser\\Evaluation\\iExprEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/iExprEvaluator.php',
|
||||
'Combodo\\iTop\\Renderer\\BlockRenderer' => __DIR__ . '/../..' . '/sources/Renderer/BlockRenderer.php',
|
||||
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
|
||||
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFormRenderer.php',
|
||||
|
||||
@@ -36,7 +36,8 @@ if ($issues) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
throw new \RuntimeException(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues)
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,211 +27,211 @@ use function array_merge;
|
||||
* affected by the LC_NUMERIC locale.
|
||||
*/
|
||||
class ConstExprEvaluator {
|
||||
/** @var callable|null */
|
||||
private $fallbackEvaluator;
|
||||
/** @var callable|null */
|
||||
private $fallbackEvaluator;
|
||||
|
||||
/**
|
||||
* Create a constant expression evaluator.
|
||||
*
|
||||
* The provided fallback evaluator is invoked whenever a subexpression cannot be evaluated. See
|
||||
* class doc comment for more information.
|
||||
*
|
||||
* @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated
|
||||
*/
|
||||
public function __construct(?callable $fallbackEvaluator = null) {
|
||||
$this->fallbackEvaluator = $fallbackEvaluator ?? function (Expr $expr) {
|
||||
throw new ConstExprEvaluationException(
|
||||
"Expression of type {$expr->getType()} cannot be evaluated"
|
||||
);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Create a constant expression evaluator.
|
||||
*
|
||||
* The provided fallback evaluator is invoked whenever a subexpression cannot be evaluated. See
|
||||
* class doc comment for more information.
|
||||
*
|
||||
* @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated
|
||||
*/
|
||||
public function __construct(?callable $fallbackEvaluator = null) {
|
||||
$this->fallbackEvaluator = $fallbackEvaluator ?? function (Expr $expr) {
|
||||
throw new ConstExprEvaluationException(
|
||||
"Expression of type {$expr->getType()} cannot be evaluated"
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Silently evaluates a constant expression into a PHP value.
|
||||
*
|
||||
* Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException.
|
||||
* The original source of the exception is available through getPrevious().
|
||||
*
|
||||
* If some part of the expression cannot be evaluated, the fallback evaluator passed to the
|
||||
* constructor will be invoked. By default, if no fallback is provided, an exception of type
|
||||
* ConstExprEvaluationException is thrown.
|
||||
*
|
||||
* See class doc comment for caveats and limitations.
|
||||
*
|
||||
* @param Expr $expr Constant expression to evaluate
|
||||
* @return mixed Result of evaluation
|
||||
*
|
||||
* @throws ConstExprEvaluationException if the expression cannot be evaluated or an error occurred
|
||||
*/
|
||||
public function evaluateSilently(Expr $expr) {
|
||||
set_error_handler(function ($num, $str, $file, $line) {
|
||||
throw new \ErrorException($str, 0, $num, $file, $line);
|
||||
});
|
||||
/**
|
||||
* Silently evaluates a constant expression into a PHP value.
|
||||
*
|
||||
* Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException.
|
||||
* The original source of the exception is available through getPrevious().
|
||||
*
|
||||
* If some part of the expression cannot be evaluated, the fallback evaluator passed to the
|
||||
* constructor will be invoked. By default, if no fallback is provided, an exception of type
|
||||
* ConstExprEvaluationException is thrown.
|
||||
*
|
||||
* See class doc comment for caveats and limitations.
|
||||
*
|
||||
* @param Expr $expr Constant expression to evaluate
|
||||
* @return mixed Result of evaluation
|
||||
*
|
||||
* @throws ConstExprEvaluationException if the expression cannot be evaluated or an error occurred
|
||||
*/
|
||||
public function evaluateSilently(Expr $expr) {
|
||||
set_error_handler(function ($num, $str, $file, $line) {
|
||||
throw new \ErrorException($str, 0, $num, $file, $line);
|
||||
});
|
||||
|
||||
try {
|
||||
return $this->evaluate($expr);
|
||||
} catch (\Throwable $e) {
|
||||
if (!$e instanceof ConstExprEvaluationException) {
|
||||
$e = new ConstExprEvaluationException(
|
||||
"An error occurred during constant expression evaluation", 0, $e);
|
||||
}
|
||||
throw $e;
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
try {
|
||||
return $this->evaluate($expr);
|
||||
} catch (\Throwable $e) {
|
||||
if (!$e instanceof ConstExprEvaluationException) {
|
||||
$e = new ConstExprEvaluationException(
|
||||
"An error occurred during constant expression evaluation", 0, $e);
|
||||
}
|
||||
throw $e;
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly evaluates a constant expression into a PHP value.
|
||||
*
|
||||
* May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these
|
||||
* into a ConstExprEvaluationException.
|
||||
*
|
||||
* If some part of the expression cannot be evaluated, the fallback evaluator passed to the
|
||||
* constructor will be invoked. By default, if no fallback is provided, an exception of type
|
||||
* ConstExprEvaluationException is thrown.
|
||||
*
|
||||
* See class doc comment for caveats and limitations.
|
||||
*
|
||||
* @param Expr $expr Constant expression to evaluate
|
||||
* @return mixed Result of evaluation
|
||||
*
|
||||
* @throws ConstExprEvaluationException if the expression cannot be evaluated
|
||||
*/
|
||||
public function evaluateDirectly(Expr $expr) {
|
||||
return $this->evaluate($expr);
|
||||
}
|
||||
/**
|
||||
* Directly evaluates a constant expression into a PHP value.
|
||||
*
|
||||
* May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these
|
||||
* into a ConstExprEvaluationException.
|
||||
*
|
||||
* If some part of the expression cannot be evaluated, the fallback evaluator passed to the
|
||||
* constructor will be invoked. By default, if no fallback is provided, an exception of type
|
||||
* ConstExprEvaluationException is thrown.
|
||||
*
|
||||
* See class doc comment for caveats and limitations.
|
||||
*
|
||||
* @param Expr $expr Constant expression to evaluate
|
||||
* @return mixed Result of evaluation
|
||||
*
|
||||
* @throws ConstExprEvaluationException if the expression cannot be evaluated
|
||||
*/
|
||||
public function evaluateDirectly(Expr $expr) {
|
||||
return $this->evaluate($expr);
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluate(Expr $expr) {
|
||||
if ($expr instanceof Scalar\Int_
|
||||
|| $expr instanceof Scalar\Float_
|
||||
|| $expr instanceof Scalar\String_
|
||||
) {
|
||||
return $expr->value;
|
||||
}
|
||||
/** @return mixed */
|
||||
private function evaluate(Expr $expr) {
|
||||
if ($expr instanceof Scalar\Int_
|
||||
|| $expr instanceof Scalar\Float_
|
||||
|| $expr instanceof Scalar\String_
|
||||
) {
|
||||
return $expr->value;
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\Array_) {
|
||||
return $this->evaluateArray($expr);
|
||||
}
|
||||
if ($expr instanceof Expr\Array_) {
|
||||
return $this->evaluateArray($expr);
|
||||
}
|
||||
|
||||
// Unary operators
|
||||
if ($expr instanceof Expr\UnaryPlus) {
|
||||
return +$this->evaluate($expr->expr);
|
||||
}
|
||||
if ($expr instanceof Expr\UnaryMinus) {
|
||||
return -$this->evaluate($expr->expr);
|
||||
}
|
||||
if ($expr instanceof Expr\BooleanNot) {
|
||||
return !$this->evaluate($expr->expr);
|
||||
}
|
||||
if ($expr instanceof Expr\BitwiseNot) {
|
||||
return ~$this->evaluate($expr->expr);
|
||||
}
|
||||
// Unary operators
|
||||
if ($expr instanceof Expr\UnaryPlus) {
|
||||
return +$this->evaluate($expr->expr);
|
||||
}
|
||||
if ($expr instanceof Expr\UnaryMinus) {
|
||||
return -$this->evaluate($expr->expr);
|
||||
}
|
||||
if ($expr instanceof Expr\BooleanNot) {
|
||||
return !$this->evaluate($expr->expr);
|
||||
}
|
||||
if ($expr instanceof Expr\BitwiseNot) {
|
||||
return ~$this->evaluate($expr->expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\BinaryOp) {
|
||||
return $this->evaluateBinaryOp($expr);
|
||||
}
|
||||
if ($expr instanceof Expr\BinaryOp) {
|
||||
return $this->evaluateBinaryOp($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\Ternary) {
|
||||
return $this->evaluateTernary($expr);
|
||||
}
|
||||
if ($expr instanceof Expr\Ternary) {
|
||||
return $this->evaluateTernary($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\ArrayDimFetch && null !== $expr->dim) {
|
||||
return $this->evaluate($expr->var)[$this->evaluate($expr->dim)];
|
||||
}
|
||||
if ($expr instanceof Expr\ArrayDimFetch && null !== $expr->dim) {
|
||||
return $this->evaluate($expr->var)[$this->evaluate($expr->dim)];
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\ConstFetch) {
|
||||
return $this->evaluateConstFetch($expr);
|
||||
}
|
||||
if ($expr instanceof Expr\ConstFetch) {
|
||||
return $this->evaluateConstFetch($expr);
|
||||
}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
private function evaluateArray(Expr\Array_ $expr): array {
|
||||
$array = [];
|
||||
foreach ($expr->items as $item) {
|
||||
if (null !== $item->key) {
|
||||
$array[$this->evaluate($item->key)] = $this->evaluate($item->value);
|
||||
} elseif ($item->unpack) {
|
||||
$array = array_merge($array, $this->evaluate($item->value));
|
||||
} else {
|
||||
$array[] = $this->evaluate($item->value);
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
private function evaluateArray(Expr\Array_ $expr): array {
|
||||
$array = [];
|
||||
foreach ($expr->items as $item) {
|
||||
if (null !== $item->key) {
|
||||
$array[$this->evaluate($item->key)] = $this->evaluate($item->value);
|
||||
} elseif ($item->unpack) {
|
||||
$array = array_merge($array, $this->evaluate($item->value));
|
||||
} else {
|
||||
$array[] = $this->evaluate($item->value);
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateTernary(Expr\Ternary $expr) {
|
||||
if (null === $expr->if) {
|
||||
return $this->evaluate($expr->cond) ?: $this->evaluate($expr->else);
|
||||
}
|
||||
/** @return mixed */
|
||||
private function evaluateTernary(Expr\Ternary $expr) {
|
||||
if (null === $expr->if) {
|
||||
return $this->evaluate($expr->cond) ?: $this->evaluate($expr->else);
|
||||
}
|
||||
|
||||
return $this->evaluate($expr->cond)
|
||||
? $this->evaluate($expr->if)
|
||||
: $this->evaluate($expr->else);
|
||||
}
|
||||
return $this->evaluate($expr->cond)
|
||||
? $this->evaluate($expr->if)
|
||||
: $this->evaluate($expr->else);
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateBinaryOp(Expr\BinaryOp $expr) {
|
||||
if ($expr instanceof Expr\BinaryOp\Coalesce
|
||||
&& $expr->left instanceof Expr\ArrayDimFetch
|
||||
) {
|
||||
// This needs to be special cased to respect BP_VAR_IS fetch semantics
|
||||
return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)]
|
||||
?? $this->evaluate($expr->right);
|
||||
}
|
||||
/** @return mixed */
|
||||
private function evaluateBinaryOp(Expr\BinaryOp $expr) {
|
||||
if ($expr instanceof Expr\BinaryOp\Coalesce
|
||||
&& $expr->left instanceof Expr\ArrayDimFetch
|
||||
) {
|
||||
// This needs to be special cased to respect BP_VAR_IS fetch semantics
|
||||
return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)]
|
||||
?? $this->evaluate($expr->right);
|
||||
}
|
||||
|
||||
// The evaluate() calls are repeated in each branch, because some of the operators are
|
||||
// short-circuiting and evaluating the RHS in advance may be illegal in that case
|
||||
$l = $expr->left;
|
||||
$r = $expr->right;
|
||||
switch ($expr->getOperatorSigil()) {
|
||||
case '&': return $this->evaluate($l) & $this->evaluate($r);
|
||||
case '|': return $this->evaluate($l) | $this->evaluate($r);
|
||||
case '^': return $this->evaluate($l) ^ $this->evaluate($r);
|
||||
case '&&': return $this->evaluate($l) && $this->evaluate($r);
|
||||
case '||': return $this->evaluate($l) || $this->evaluate($r);
|
||||
case '??': return $this->evaluate($l) ?? $this->evaluate($r);
|
||||
case '.': return $this->evaluate($l) . $this->evaluate($r);
|
||||
case '/': return $this->evaluate($l) / $this->evaluate($r);
|
||||
case '==': return $this->evaluate($l) == $this->evaluate($r);
|
||||
case '>': return $this->evaluate($l) > $this->evaluate($r);
|
||||
case '>=': return $this->evaluate($l) >= $this->evaluate($r);
|
||||
case '===': return $this->evaluate($l) === $this->evaluate($r);
|
||||
case 'and': return $this->evaluate($l) and $this->evaluate($r);
|
||||
case 'or': return $this->evaluate($l) or $this->evaluate($r);
|
||||
case 'xor': return $this->evaluate($l) xor $this->evaluate($r);
|
||||
case '-': return $this->evaluate($l) - $this->evaluate($r);
|
||||
case '%': return $this->evaluate($l) % $this->evaluate($r);
|
||||
case '*': return $this->evaluate($l) * $this->evaluate($r);
|
||||
case '!=': return $this->evaluate($l) != $this->evaluate($r);
|
||||
case '!==': return $this->evaluate($l) !== $this->evaluate($r);
|
||||
case '+': return $this->evaluate($l) + $this->evaluate($r);
|
||||
case '**': return $this->evaluate($l) ** $this->evaluate($r);
|
||||
case '<<': return $this->evaluate($l) << $this->evaluate($r);
|
||||
case '>>': return $this->evaluate($l) >> $this->evaluate($r);
|
||||
case '<': return $this->evaluate($l) < $this->evaluate($r);
|
||||
case '<=': return $this->evaluate($l) <= $this->evaluate($r);
|
||||
case '<=>': return $this->evaluate($l) <=> $this->evaluate($r);
|
||||
case '|>':
|
||||
$lval = $this->evaluate($l);
|
||||
return $this->evaluate($r)($lval);
|
||||
}
|
||||
// The evaluate() calls are repeated in each branch, because some of the operators are
|
||||
// short-circuiting and evaluating the RHS in advance may be illegal in that case
|
||||
$l = $expr->left;
|
||||
$r = $expr->right;
|
||||
switch ($expr->getOperatorSigil()) {
|
||||
case '&': return $this->evaluate($l) & $this->evaluate($r);
|
||||
case '|': return $this->evaluate($l) | $this->evaluate($r);
|
||||
case '^': return $this->evaluate($l) ^ $this->evaluate($r);
|
||||
case '&&': return $this->evaluate($l) && $this->evaluate($r);
|
||||
case '||': return $this->evaluate($l) || $this->evaluate($r);
|
||||
case '??': return $this->evaluate($l) ?? $this->evaluate($r);
|
||||
case '.': return $this->evaluate($l) . $this->evaluate($r);
|
||||
case '/': return $this->evaluate($l) / $this->evaluate($r);
|
||||
case '==': return $this->evaluate($l) == $this->evaluate($r);
|
||||
case '>': return $this->evaluate($l) > $this->evaluate($r);
|
||||
case '>=': return $this->evaluate($l) >= $this->evaluate($r);
|
||||
case '===': return $this->evaluate($l) === $this->evaluate($r);
|
||||
case 'and': return $this->evaluate($l) and $this->evaluate($r);
|
||||
case 'or': return $this->evaluate($l) or $this->evaluate($r);
|
||||
case 'xor': return $this->evaluate($l) xor $this->evaluate($r);
|
||||
case '-': return $this->evaluate($l) - $this->evaluate($r);
|
||||
case '%': return $this->evaluate($l) % $this->evaluate($r);
|
||||
case '*': return $this->evaluate($l) * $this->evaluate($r);
|
||||
case '!=': return $this->evaluate($l) != $this->evaluate($r);
|
||||
case '!==': return $this->evaluate($l) !== $this->evaluate($r);
|
||||
case '+': return $this->evaluate($l) + $this->evaluate($r);
|
||||
case '**': return $this->evaluate($l) ** $this->evaluate($r);
|
||||
case '<<': return $this->evaluate($l) << $this->evaluate($r);
|
||||
case '>>': return $this->evaluate($l) >> $this->evaluate($r);
|
||||
case '<': return $this->evaluate($l) < $this->evaluate($r);
|
||||
case '<=': return $this->evaluate($l) <= $this->evaluate($r);
|
||||
case '<=>': return $this->evaluate($l) <=> $this->evaluate($r);
|
||||
case '|>':
|
||||
$lval = $this->evaluate($l);
|
||||
return $this->evaluate($r)($lval);
|
||||
}
|
||||
|
||||
throw new \Exception('Should not happen');
|
||||
}
|
||||
throw new \Exception('Should not happen');
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateConstFetch(Expr\ConstFetch $expr) {
|
||||
$name = $expr->name->toLowerString();
|
||||
switch ($name) {
|
||||
case 'null': return null;
|
||||
case 'false': return false;
|
||||
case 'true': return true;
|
||||
}
|
||||
/** @return mixed */
|
||||
private function evaluateConstFetch(Expr\ConstFetch $expr) {
|
||||
$name = $expr->name->toLowerString();
|
||||
switch ($name) {
|
||||
case 'null': return null;
|
||||
case 'false': return false;
|
||||
case 'true': return true;
|
||||
}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator;
|
||||
|
||||
require_once(APPROOT.'setup/modulediscovery/ModuleFileReader.php');
|
||||
|
||||
class MissingDependencyException extends CoreException
|
||||
{
|
||||
/**
|
||||
@@ -105,6 +109,9 @@ class ModuleDiscovery
|
||||
*/
|
||||
public static function AddModule($sFilePath, $sId, $aArgs)
|
||||
{
|
||||
if (is_null($aArgs)||! is_array($aArgs)){
|
||||
throw new ModuleFileReaderException("Error parsing module file args", 0, null, $sFilePath);
|
||||
}
|
||||
if (!array_key_exists('itop_version', $aArgs))
|
||||
{
|
||||
// Assume 1.0.2
|
||||
@@ -115,7 +122,7 @@ class ModuleDiscovery
|
||||
if (!array_key_exists($sArgName, $aArgs))
|
||||
{
|
||||
throw new Exception("Module '$sId': missing argument '$sArgName'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aArgs['root_dir'] = dirname($sFilePath);
|
||||
@@ -218,7 +225,7 @@ class ModuleDiscovery
|
||||
* @param array $aModulesToLoad List of modules to search for, defaults to all if omitted
|
||||
* @return array
|
||||
* @throws \MissingDependencyException
|
||||
*/
|
||||
*/
|
||||
public static function OrderModulesByDependencies($aModules, $bAbortOnMissingDependency = false, $aModulesToLoad = null)
|
||||
{
|
||||
// Order the modules to take into account their inter-dependencies
|
||||
@@ -349,19 +356,19 @@ class ModuleDiscovery
|
||||
if (version_compare($sCurrentVersion, $sExpectedVersion, $sOperator))
|
||||
{
|
||||
$aReplacements[$sModuleId] = '(true)'; // Add parentheses to protect against invalid condition causing
|
||||
// a function call that results in a runtime fatal error
|
||||
// a function call that results in a runtime fatal error
|
||||
}
|
||||
else
|
||||
{
|
||||
$aReplacements[$sModuleId] = '(false)'; // Add parentheses to protect against invalid condition causing
|
||||
// a function call that results in a runtime fatal error
|
||||
// a function call that results in a runtime fatal error
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// module is not present
|
||||
$aReplacements[$sModuleId] = '(false)'; // Add parentheses to protect against invalid condition causing
|
||||
// a function call that results in a runtime fatal error
|
||||
// a function call that results in a runtime fatal error
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,10 +392,10 @@ class ModuleDiscovery
|
||||
else
|
||||
{
|
||||
$sBooleanExpr = str_replace(array_keys($aReplacements), array_values($aReplacements), $sDepString);
|
||||
$bOk = @eval('$bResult = '.$sBooleanExpr.'; return true;');
|
||||
if ($bOk == false)
|
||||
{
|
||||
SetupLog::Warning("Eval of '$sBooleanExpr' returned false");
|
||||
try{
|
||||
$bResult = PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($sBooleanExpr);
|
||||
} catch(ModuleFileReaderException $e){
|
||||
//logged already
|
||||
echo "Failed to parse the boolean Expression = '$sBooleanExpr'<br/>";
|
||||
}
|
||||
}
|
||||
@@ -496,42 +503,12 @@ class ModuleDiscovery
|
||||
else if (preg_match('/^module\.(.*).php$/i', $sFile, $aMatches))
|
||||
{
|
||||
self::SetModulePath($sRelDir);
|
||||
try
|
||||
{
|
||||
$sModuleFileContents = file_get_contents($sDirectory.'/'.$sFile);
|
||||
$sModuleFileContents = str_replace(array('<?php', '?>'), '', $sModuleFileContents);
|
||||
$sModuleFileContents = str_replace('__FILE__', "'".addslashes($sDirectory.'/'.$sFile)."'", $sModuleFileContents);
|
||||
preg_match_all('/class ([A-Za-z0-9_]+) extends ([A-Za-z0-9_]+)/', $sModuleFileContents, $aMatches);
|
||||
//print_r($aMatches);
|
||||
$idx = 0;
|
||||
foreach($aMatches[1] as $sClassName)
|
||||
{
|
||||
if (class_exists($sClassName))
|
||||
{
|
||||
// rename the class inside the code to prevent a "duplicate class" declaration
|
||||
// and change its parent class as well so that nobody will find it and try to execute it
|
||||
$sModuleFileContents = str_replace($sClassName.' extends '.$aMatches[2][$idx], $sClassName.'_'.($iDummyClassIndex++).' extends DummyHandler', $sModuleFileContents);
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
$bRet = eval($sModuleFileContents);
|
||||
|
||||
if ($bRet === false)
|
||||
{
|
||||
SetupLog::Warning("Eval of $sRelDir/$sFile returned false");
|
||||
}
|
||||
|
||||
//echo "<p>Done.</p>\n";
|
||||
}
|
||||
catch(ParseError $e)
|
||||
{
|
||||
// PHP 7
|
||||
SetupLog::Warning("Eval of $sRelDir/$sFile caused an exception: ".$e->getMessage()." at line ".$e->getLine());
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// Continue...
|
||||
SetupLog::Warning("Eval of $sRelDir/$sFile caused an exception: ".$e->getMessage());
|
||||
$sModuleFilePath = $sDirectory.'/'.$sFile;
|
||||
try {
|
||||
$aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sDirectory.'/'.$sFile);
|
||||
SetupWebPage::AddModule($sModuleFilePath, $aModuleInfo[1], $aModuleInfo[2]);
|
||||
} catch(ModuleFileReaderException $e){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
155
setup/modulediscovery/ModuleFileParser.php
Normal file
155
setup/modulediscovery/ModuleFileParser.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\ParserFactory;
|
||||
require_once APPROOT . 'sources/PhpParser/Evaluation/PhpExpressionEvaluator.php';
|
||||
|
||||
class ModuleFileParser {
|
||||
private static ModuleFileParser $oInstance;
|
||||
|
||||
protected function __construct() {
|
||||
}
|
||||
|
||||
final public static function GetInstance(): ModuleFileParser {
|
||||
if (!isset(static::$oInstance)) {
|
||||
static::$oInstance = new static();
|
||||
}
|
||||
|
||||
return static::$oInstance;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?ModuleFileParser $oInstance): void {
|
||||
static::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPhpContent
|
||||
*
|
||||
* @return \PhpParser\Node\Stmt[]|null
|
||||
*/
|
||||
public function ParsePhpCode(string $sPhpContent): ?array
|
||||
{
|
||||
$oParser = (new ParserFactory())->createForNewestSupportedVersion();
|
||||
return $oParser->parse($sPhpContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sModuleFilePath
|
||||
* @param \PhpParser\Node\Expr\Assign $oAssignation
|
||||
*
|
||||
* @return array|null
|
||||
* @throws \ModuleFileReaderException
|
||||
*/
|
||||
public function GetModuleInformationFromAddModuleCall(string $sModuleFilePath, \PhpParser\Node\Stmt\Expression $oExpression) : ?array
|
||||
{
|
||||
/** @var Assign $oAssignation */
|
||||
$oAssignation = $oExpression->expr;
|
||||
if (false === ($oAssignation instanceof PhpParser\Node\Expr\StaticCall)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var PhpParser\Node\Expr\StaticCall $oAssignation */
|
||||
|
||||
if ("SetupWebPage" !== $oAssignation?->class?->name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ("AddModule" !== $oAssignation?->name?->name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$aArgs = $oAssignation?->args;
|
||||
if (count($aArgs) != 3) {
|
||||
throw new ModuleFileReaderException("Not enough parameters when calling SetupWebPage::AddModule", 0, null, $sModuleFilePath);
|
||||
}
|
||||
|
||||
$oModuleId = $aArgs[1];
|
||||
if (false === ($oModuleId instanceof PhpParser\Node\Arg)) {
|
||||
throw new ModuleFileReaderException("2nd parameter to SetupWebPage::AddModule call issue: " . get_class($oModuleId), 0, null, $sModuleFilePath);
|
||||
}
|
||||
|
||||
/** @var PhpParser\Node\Arg $oModuleId */
|
||||
if (false === ($oModuleId->value instanceof PhpParser\Node\Scalar\String_)) {
|
||||
throw new ModuleFileReaderException("2nd parameter to SetupWebPage::AddModule not a string: " . get_class($oModuleId->value), 0, null, $sModuleFilePath);
|
||||
}
|
||||
|
||||
$sModuleId = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oModuleId->value);
|
||||
|
||||
$oModuleConfigInfo = $aArgs[2];
|
||||
if (false === ($oModuleConfigInfo instanceof PhpParser\Node\Arg)) {
|
||||
throw new ModuleFileReaderException("3rd parameter to SetupWebPage::AddModule call issue: " . get_class($oModuleConfigInfo), 0, null, $sModuleFilePath);
|
||||
}
|
||||
|
||||
/** @var PhpParser\Node\Arg $oModuleConfigInfo */
|
||||
if (false === ($oModuleConfigInfo->value instanceof PhpParser\Node\Expr\Array_)) {
|
||||
throw new ModuleFileReaderException("3rd parameter to SetupWebPage::AddModule not an array: " . get_class($oModuleConfigInfo->value), 0, null, $sModuleFilePath);
|
||||
}
|
||||
|
||||
$aModuleConfig = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oModuleConfigInfo->value);
|
||||
|
||||
if (! is_array($aModuleConfig)){
|
||||
throw new ModuleFileReaderException("3rd parameter to SetupWebPage::AddModule not an array: " . get_class($oModuleConfigInfo->value), 0, null, $sModuleFilePath);
|
||||
}
|
||||
|
||||
return [
|
||||
$sModuleFilePath,
|
||||
$sModuleId,
|
||||
$aModuleConfig,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sModuleFilePath
|
||||
* @param \PhpParser\Node\Stmt\If_ $oNode
|
||||
*
|
||||
* @return array|null
|
||||
* @throws \ModuleFileReaderException
|
||||
*/
|
||||
public function GetModuleInformationFromIf(string $sModuleFilePath, \PhpParser\Node\Stmt\If_ $oNode) : ?array
|
||||
{
|
||||
$bCondition = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oNode->cond);
|
||||
if ($bCondition) {
|
||||
foreach ($oNode->stmts as $oSubNode) {
|
||||
if ($oSubNode instanceof \PhpParser\Node\Stmt\Expression) {
|
||||
$aModuleConfig = $this->GetModuleInformationFromAddModuleCall($sModuleFilePath, $oSubNode);
|
||||
if (!is_null($aModuleConfig)) {
|
||||
return $aModuleConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! is_null($oNode->elseifs)) {
|
||||
foreach ($oNode->elseifs as $oElseIfSubNode) {
|
||||
/** @var \PhpParser\Node\Stmt\ElseIf_ $oElseIfSubNode */
|
||||
$bCondition = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oElseIfSubNode->cond);
|
||||
if ($bCondition) {
|
||||
return $this->GetModuleConfigurationFromStatement($sModuleFilePath, $oElseIfSubNode->stmts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_null($oNode->else)) {
|
||||
return $this->GetModuleConfigurationFromStatement($sModuleFilePath, $oNode->else->stmts);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetModuleConfigurationFromStatement(string $sModuleFilePath, array $aStmts) : ?array
|
||||
{
|
||||
foreach ($aStmts as $oSubNode) {
|
||||
if ($oSubNode instanceof \PhpParser\Node\Stmt\Expression) {
|
||||
$aModuleConfig = $this->GetModuleInformationFromAddModuleCall($sModuleFilePath, $oSubNode);
|
||||
if (!is_null($aModuleConfig)) {
|
||||
return $aModuleConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
167
setup/modulediscovery/ModuleFileReader.php
Normal file
167
setup/modulediscovery/ModuleFileReader.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/ModuleFileParser.php';
|
||||
require_once __DIR__ . '/ModuleFileReaderException.php';
|
||||
|
||||
class ModuleFileReader {
|
||||
private static ModuleFileReader $oInstance;
|
||||
private static int $iDummyClassIndex = 0;
|
||||
|
||||
protected function __construct() {
|
||||
}
|
||||
|
||||
final public static function GetInstance(): ModuleFileReader {
|
||||
if (!isset(static::$oInstance)) {
|
||||
static::$oInstance = new static();
|
||||
}
|
||||
|
||||
return static::$oInstance;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?ModuleFileReader $oInstance): void {
|
||||
static::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the information from a module file (module.xxx.php)
|
||||
* @param string $sModuleFile
|
||||
* @return array
|
||||
* @throws ModuleFileReaderException
|
||||
*/
|
||||
public function ReadModuleFileInformation(string $sModuleFilePath) : array
|
||||
{
|
||||
try
|
||||
{
|
||||
$aNodes = ModuleFileParser::GetInstance()->ParsePhpCode(file_get_contents($sModuleFilePath));
|
||||
}
|
||||
catch (PhpParser\Error $e) {
|
||||
throw new \ModuleFileReaderException($e->getMessage(), 0, $e, $sModuleFilePath);
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($aNodes as $sKey => $oNode) {
|
||||
if ($oNode instanceof \PhpParser\Node\Stmt\Expression) {
|
||||
$aModuleInfo = ModuleFileParser::GetInstance()->GetModuleInformationFromAddModuleCall($sModuleFilePath, $oNode);
|
||||
if (! is_null($aModuleInfo)){
|
||||
$this->CompleteModuleInfoWithFilePath($aModuleInfo);
|
||||
return $aModuleInfo;
|
||||
}
|
||||
}
|
||||
|
||||
if ($oNode instanceof PhpParser\Node\Stmt\If_) {
|
||||
$aModuleInfo = ModuleFileParser::GetInstance()->GetModuleInformationFromIf($sModuleFilePath, $oNode);
|
||||
if (! is_null($aModuleInfo)){
|
||||
$this->CompleteModuleInfoWithFilePath($aModuleInfo);
|
||||
return $aModuleInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(ModuleFileReaderException $e) {
|
||||
// Continue...
|
||||
throw $e;
|
||||
} catch(Exception $e) {
|
||||
// Continue...
|
||||
throw new ModuleFileReaderException("Eval of $sModuleFilePath caused an exception: ".$e->getMessage(), 0, $e, $sModuleFilePath);
|
||||
}
|
||||
|
||||
throw new ModuleFileReaderException("No proper call to SetupWebPage::AddModule found in module file", 0, null, $sModuleFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the information from a module file (module.xxx.php)
|
||||
* Warning: this method is using eval() function to load the ModuleInstallerAPI classes.
|
||||
* Current method is never called at design/runtime. It is acceptable to use it during setup only.
|
||||
* @param string $sModuleFile
|
||||
* @return array
|
||||
* @throws ModuleFileReaderException
|
||||
*/
|
||||
public function ReadModuleFileInformationUnsafe(string $sModuleFilePath) : array
|
||||
{
|
||||
$aModuleInfo = []; // will be filled by the "eval" line below...
|
||||
try
|
||||
{
|
||||
$aMatches = [];
|
||||
$sModuleFileContents = file_get_contents($sModuleFilePath);
|
||||
$sModuleFileContents = str_replace(['<?php', '?>'], '', $sModuleFileContents);
|
||||
$sModuleFileContents = str_replace('__FILE__', "'".addslashes($sModuleFilePath)."'", $sModuleFileContents);
|
||||
preg_match_all('/class ([A-Za-z0-9_]+) extends ([A-Za-z0-9_]+)/', $sModuleFileContents, $aMatches);
|
||||
//print_r($aMatches);
|
||||
$idx = 0;
|
||||
foreach($aMatches[1] as $sClassName)
|
||||
{
|
||||
if (class_exists($sClassName))
|
||||
{
|
||||
// rename any class declaration inside the code to prevent a "duplicate class" declaration
|
||||
// and change its parent class as well so that nobody will find it and try to execute it
|
||||
// Note: don't use the same naming scheme as ModuleDiscovery otherwise you 'll have the duplicate class error again !!
|
||||
$sModuleFileContents = str_replace($sClassName.' extends '.$aMatches[2][$idx], $sClassName.'_Ext_'.(ModuleFileReader::$iDummyClassIndex++).' extends DummyHandler', $sModuleFileContents);
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
// Replace the main function call by an assignment to a variable, as an array...
|
||||
$sModuleFileContents = str_replace(['SetupWebPage::AddModule', 'ModuleDiscovery::AddModule'], '$aModuleInfo = array', $sModuleFileContents);
|
||||
eval($sModuleFileContents); // Assigns $aModuleInfo
|
||||
|
||||
if (count($aModuleInfo) === 0)
|
||||
{
|
||||
throw new ModuleFileReaderException("Eval of $sModuleFilePath did not return the expected information...");
|
||||
}
|
||||
|
||||
$this->CompleteModuleInfoWithFilePath($aModuleInfo);
|
||||
}
|
||||
catch(ModuleFileReaderException $e)
|
||||
{
|
||||
// Continue...
|
||||
throw $e;
|
||||
}
|
||||
catch(ParseError $e)
|
||||
{
|
||||
// Continue...
|
||||
throw new ModuleFileReaderException("Eval of $sModuleFilePath caused a parse error: ".$e->getMessage()." at line ".$e->getLine());
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// Continue...
|
||||
throw new ModuleFileReaderException("Eval of $sModuleFilePath caused an exception: ".$e->getMessage(), 0, $e);
|
||||
}
|
||||
return $aModuleInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Internal trick: additional path is added into the module info structure to handle ModuleInstallerAPI execution during setup
|
||||
* @param array &$aModuleInfo
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function CompleteModuleInfoWithFilePath(array &$aModuleInfo)
|
||||
{
|
||||
if (count($aModuleInfo)==3) {
|
||||
$aModuleInfo[2]['module_file_path'] = $aModuleInfo[0];
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAndCheckModuleInstallerClass($aModuleInfo) : ?string
|
||||
{
|
||||
if (! isset($aModuleInfo['installer'])){
|
||||
return null;
|
||||
}
|
||||
|
||||
$sModuleInstallerClass = $aModuleInfo['installer'];
|
||||
if (!class_exists($sModuleInstallerClass)) {
|
||||
$sModuleFilePath = $aModuleInfo['module_file_path'];
|
||||
$this->ReadModuleFileInformationUnsafe($sModuleFilePath);
|
||||
}
|
||||
|
||||
if (!class_exists($sModuleInstallerClass))
|
||||
{
|
||||
throw new CoreException("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']);
|
||||
}
|
||||
if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI'))
|
||||
{
|
||||
throw new CoreException("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']);
|
||||
}
|
||||
|
||||
return $sModuleInstallerClass;
|
||||
}
|
||||
}
|
||||
23
setup/modulediscovery/ModuleFileReaderException.php
Normal file
23
setup/modulediscovery/ModuleFileReaderException.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
class ModuleFileReaderException extends Exception
|
||||
{
|
||||
/**
|
||||
* ModuleFileReaderException constructor.
|
||||
*
|
||||
* @param string $sMessage
|
||||
* @param int $iHttpCode
|
||||
* @param Exception|null $oPrevious
|
||||
*/
|
||||
public function __construct($sMessage, $iHttpCode = 0, Exception $oPrevious = null, $sModuleFile = null)
|
||||
{
|
||||
$e = new \Exception("");
|
||||
|
||||
$aContext = ['previous' => $oPrevious?->getMessage(), 'stack' => $e->getTraceAsString()];
|
||||
if (!is_null($sModuleFile)) {
|
||||
$aContext['module_file'] = $sModuleFile;
|
||||
}
|
||||
SetupLog::Warning($sMessage, null, $aContext);
|
||||
parent::__construct($sMessage, $iHttpCode, $oPrevious);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator;
|
||||
|
||||
require_once APPROOT."setup/modulediscovery.class.inc.php";
|
||||
require_once APPROOT.'setup/modelfactory.class.inc.php';
|
||||
require_once APPROOT.'setup/compiler.class.inc.php';
|
||||
@@ -202,10 +204,10 @@ class RunTimeEnvironment
|
||||
if (!in_array($sModuleAppVersion, array('1.0.0', '1.0.1', '1.0.2')))
|
||||
{
|
||||
// This module is NOT compatible with the current version
|
||||
$aModuleInfo['install'] = array(
|
||||
'flag' => MODULE_ACTION_IMPOSSIBLE,
|
||||
'message' => 'the module is not compatible with the current version of the application'
|
||||
);
|
||||
$aModuleInfo['install'] = array(
|
||||
'flag' => MODULE_ACTION_IMPOSSIBLE,
|
||||
'message' => 'the module is not compatible with the current version of the application'
|
||||
);
|
||||
}
|
||||
elseif ($aModuleInfo['mandatory'])
|
||||
{
|
||||
@@ -457,20 +459,16 @@ class RunTimeEnvironment
|
||||
{
|
||||
if (!array_key_exists($oModule->GetName(), $aRet) && $oModule->IsAutoSelect())
|
||||
{
|
||||
try
|
||||
{
|
||||
$bSelected = false;
|
||||
SetupInfo::SetSelectedModules($aRet);
|
||||
eval('$bSelected = ('.$oModule->GetAutoSelect().');');
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$bSelected = false;
|
||||
}
|
||||
if ($bSelected)
|
||||
{
|
||||
$aRet[$oModule->GetName()] = $oModule; // store the Id of the selected module
|
||||
$bModuleAdded = true;
|
||||
SetupInfo::SetSelectedModules($aRet);
|
||||
try{
|
||||
$bSelected = PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($oModule->GetAutoSelect());
|
||||
if ($bSelected)
|
||||
{
|
||||
$aRet[$oModule->GetName()] = $oModule; // store the Id of the selected module
|
||||
$bModuleAdded = true;
|
||||
}
|
||||
} catch(ModuleFileReaderException $e){
|
||||
//do nothing. logged already
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -977,8 +975,8 @@ class RunTimeEnvironment
|
||||
$this->CommitDir(
|
||||
APPROOT.'env-'.$this->sTargetEnv,
|
||||
APPROOT.'env-'.$this->sFinalEnv,
|
||||
true,
|
||||
false
|
||||
true,
|
||||
false
|
||||
);
|
||||
|
||||
// Move the config file
|
||||
@@ -1045,7 +1043,7 @@ class RunTimeEnvironment
|
||||
* @param $sSource
|
||||
* @param $sDest
|
||||
* @param boolean $bSourceMustExist
|
||||
* @param boolean $bRemoveSource If true $sSource will be removed, otherwise $sSource will just be emptied
|
||||
* @param boolean $bRemoveSource If true $sSource will be removed, otherwise $sSource will just be emptied
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function CommitDir($sSource, $sDest, $bSourceMustExist = true, $bRemoveSource = true)
|
||||
@@ -1080,41 +1078,59 @@ class RunTimeEnvironment
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the given handler method for all selected modules having an installation handler
|
||||
* @param array[] $aAvailableModules
|
||||
* @param string[] $aSelectedModules
|
||||
* @param string $sHandlerName
|
||||
* @throws CoreException
|
||||
*/
|
||||
/**
|
||||
* Call the given handler method for all selected modules having an installation handler
|
||||
* @param array[] $aAvailableModules
|
||||
* @param string[] $aSelectedModules
|
||||
* @param string $sHandlerName
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function CallInstallerHandlers($aAvailableModules, $aSelectedModules, $sHandlerName)
|
||||
{
|
||||
foreach($aAvailableModules as $sModuleId => $aModule)
|
||||
{
|
||||
if (($sModuleId != ROOT_MODULE) && in_array($sModuleId, $aSelectedModules) &&
|
||||
isset($aAvailableModules[$sModuleId]['installer']) )
|
||||
{
|
||||
$sModuleInstallerClass = $aAvailableModules[$sModuleId]['installer'];
|
||||
SetupLog::Info("Calling Module Handler: $sModuleInstallerClass::$sHandlerName(oConfig, {$aModule['version_db']}, {$aModule['version_code']})");
|
||||
$aCallSpec = array($sModuleInstallerClass, $sHandlerName);
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
try {
|
||||
call_user_func_array($aCallSpec, array(MetaModel::GetConfig(), $aModule['version_db'], $aModule['version_code']));
|
||||
} catch (Exception $e) {
|
||||
$sErrorMessage = "Module $sModuleId : error when calling module installer class $sModuleInstallerClass for $sHandlerName handler";
|
||||
$aExceptionContextData = [
|
||||
'ModulelId' => $sModuleId,
|
||||
'ModuleInstallerClass' => $sModuleInstallerClass,
|
||||
'ModuleInstallerHandler' => $sHandlerName,
|
||||
'ExceptionClass' => get_class($e),
|
||||
'ExceptionMessage' => $e->getMessage(),
|
||||
];
|
||||
throw new CoreException($sErrorMessage, $aExceptionContextData, '', $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach($aAvailableModules as $sModuleId => $aModule)
|
||||
{
|
||||
if (($sModuleId != ROOT_MODULE) && in_array($sModuleId, $aSelectedModules))
|
||||
{
|
||||
$aArgs = [MetaModel::GetConfig(), $aModule['version_db'], $aModule['version_code']];
|
||||
RunTimeEnvironment::CallInstallerHandler($aAvailableModules[$sModuleId], $sHandlerName, $aArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the given handler method for all selected modules having an installation handler
|
||||
*
|
||||
* @param array $aModuleInfo
|
||||
* @param string $sHandlerName
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @throws CoreException
|
||||
*/
|
||||
public static function CallInstallerHandler(array $aModuleInfo, $sHandlerName, array $aArgs)
|
||||
{
|
||||
$sModuleInstallerClass = ModuleFileReader::GetInstance()->GetAndCheckModuleInstallerClass($aModuleInfo);
|
||||
if (is_null($sModuleInstallerClass)){
|
||||
return;
|
||||
}
|
||||
|
||||
SetupLog::Info("Calling Module Handler: $sModuleInstallerClass::$sHandlerName", null, $aArgs);
|
||||
$aCallSpec = [$sModuleInstallerClass, $sHandlerName];
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
try {
|
||||
call_user_func_array($aCallSpec, $aArgs);
|
||||
} catch (Exception $e) {
|
||||
$sErrorMessage = "Module $sModuleId : error when calling module installer class $sModuleInstallerClass for $sHandlerName handler";
|
||||
$aExceptionContextData = [
|
||||
'ModulelId' => $sModuleId,
|
||||
'ModuleInstallerClass' => $sModuleInstallerClass,
|
||||
'ModuleInstallerHandler' => $sHandlerName,
|
||||
'ExceptionClass' => get_class($e),
|
||||
'ExceptionMessage' => $e->getMessage(),
|
||||
];
|
||||
throw new CoreException($sErrorMessage, $aExceptionContextData, '', $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1143,64 +1159,64 @@ class RunTimeEnvironment
|
||||
if ($aModule['version_db'] != '') {
|
||||
// Simulate the load of the previously loaded XML files to get the mapping of the keys
|
||||
if ($bSampleData) {
|
||||
$aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']);
|
||||
$aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.sample']);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load only structural data
|
||||
$aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bSampleData)
|
||||
{
|
||||
$aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']);
|
||||
$aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.sample']);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load only structural data
|
||||
$aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']);
|
||||
$aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.sample']);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load only structural data
|
||||
$aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bSampleData)
|
||||
{
|
||||
$aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']);
|
||||
$aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.sample']);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load only structural data
|
||||
$aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate the load of the previously loaded files, in order to initialize
|
||||
// the mapping between the identifiers in the XML and the actual identifiers
|
||||
// in the current database
|
||||
foreach($aPreviouslyLoadedFiles as $sFileRelativePath)
|
||||
{
|
||||
$sFileName = APPROOT.$sFileRelativePath;
|
||||
SetupLog::Info("Loading file: $sFileName (just to get the keys mapping)");
|
||||
if (empty($sFileName) || !file_exists($sFileName))
|
||||
{
|
||||
throw(new Exception("File $sFileName does not exist"));
|
||||
}
|
||||
// Simulate the load of the previously loaded files, in order to initialize
|
||||
// the mapping between the identifiers in the XML and the actual identifiers
|
||||
// in the current database
|
||||
foreach($aPreviouslyLoadedFiles as $sFileRelativePath)
|
||||
{
|
||||
$sFileName = APPROOT.$sFileRelativePath;
|
||||
SetupLog::Info("Loading file: $sFileName (just to get the keys mapping)");
|
||||
if (empty($sFileName) || !file_exists($sFileName))
|
||||
{
|
||||
throw(new Exception("File $sFileName does not exist"));
|
||||
}
|
||||
|
||||
$oDataLoader->LoadFile($sFileName, true);
|
||||
$sResult = sprintf("loading of %s done.", basename($sFileName));
|
||||
SetupLog::Info($sResult);
|
||||
}
|
||||
$oDataLoader->LoadFile($sFileName, true);
|
||||
$sResult = sprintf("loading of %s done.", basename($sFileName));
|
||||
SetupLog::Info($sResult);
|
||||
}
|
||||
|
||||
foreach($aFiles as $sFileRelativePath)
|
||||
{
|
||||
$sFileName = APPROOT.$sFileRelativePath;
|
||||
SetupLog::Info("Loading file: $sFileName");
|
||||
if (empty($sFileName) || !file_exists($sFileName))
|
||||
{
|
||||
throw(new Exception("File $sFileName does not exist"));
|
||||
}
|
||||
foreach($aFiles as $sFileRelativePath)
|
||||
{
|
||||
$sFileName = APPROOT.$sFileRelativePath;
|
||||
SetupLog::Info("Loading file: $sFileName");
|
||||
if (empty($sFileName) || !file_exists($sFileName))
|
||||
{
|
||||
throw(new Exception("File $sFileName does not exist"));
|
||||
}
|
||||
|
||||
$oDataLoader->LoadFile($sFileName);
|
||||
$sResult = sprintf("loading of %s done.", basename($sFileName));
|
||||
SetupLog::Info($sResult);
|
||||
}
|
||||
$oDataLoader->LoadFile($sFileName);
|
||||
$sResult = sprintf("loading of %s done.", basename($sFileName));
|
||||
SetupLog::Info($sResult);
|
||||
}
|
||||
|
||||
$oDataLoader->EndSession();
|
||||
$oDataLoader->EndSession();
|
||||
SetupLog::Info("ending data load session");
|
||||
}
|
||||
|
||||
@@ -1213,12 +1229,12 @@ class RunTimeEnvironment
|
||||
*/
|
||||
protected static function MergeWithRelativeDir($aSourceArray, $sBaseDir, $aFilesToMerge)
|
||||
{
|
||||
$aToMerge = array();
|
||||
foreach($aFilesToMerge as $sFile)
|
||||
{
|
||||
$aToMerge[] = $sBaseDir.'/'.$sFile;
|
||||
}
|
||||
return array_merge($aSourceArray, $aToMerge);
|
||||
$aToMerge = array();
|
||||
foreach($aFilesToMerge as $sFile)
|
||||
{
|
||||
$aToMerge[] = $sBaseDir.'/'.$sFile;
|
||||
}
|
||||
return array_merge($aSourceArray, $aToMerge);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1227,40 +1243,40 @@ class RunTimeEnvironment
|
||||
* @throws Exception
|
||||
* @return string
|
||||
*/
|
||||
public function CheckMetaModel()
|
||||
{
|
||||
$iCount = 0;
|
||||
$fStart = microtime(true);
|
||||
foreach(MetaModel::GetClasses() as $sClass)
|
||||
{
|
||||
if (false == MetaModel::HasTable($sClass) && MetaModel::IsAbstract($sClass))
|
||||
{
|
||||
//if a class is not persisted and is abstract, the code below would crash. Needed by the class AbstractRessource. This is tolerable to skip this because we check the setup process integrity, not the datamodel integrity.
|
||||
continue;
|
||||
}
|
||||
public function CheckMetaModel()
|
||||
{
|
||||
$iCount = 0;
|
||||
$fStart = microtime(true);
|
||||
foreach(MetaModel::GetClasses() as $sClass)
|
||||
{
|
||||
if (false == MetaModel::HasTable($sClass) && MetaModel::IsAbstract($sClass))
|
||||
{
|
||||
//if a class is not persisted and is abstract, the code below would crash. Needed by the class AbstractRessource. This is tolerable to skip this because we check the setup process integrity, not the datamodel integrity.
|
||||
continue;
|
||||
}
|
||||
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$oSearch->SetShowObsoleteData(false);
|
||||
$oSQLQuery = $oSearch->GetSQLQueryStructure(null, false);
|
||||
$sViewName = MetaModel::DBGetView($sClass);
|
||||
if (strlen($sViewName) > 64)
|
||||
{
|
||||
throw new Exception("Class name too long for class: '$sClass'. The name of the corresponding view ($sViewName) would exceed MySQL's limit for the name of a table (64 characters).");
|
||||
}
|
||||
$sTableName = MetaModel::DBGetTable($sClass);
|
||||
if (strlen($sTableName) > 64)
|
||||
{
|
||||
throw new Exception("Table name too long for class: '$sClass'. The name of the corresponding MySQL table ($sTableName) would exceed MySQL's limit for the name of a table (64 characters).");
|
||||
}
|
||||
$iTableCount = $oSQLQuery->CountTables();
|
||||
if ($iTableCount > 61)
|
||||
{
|
||||
throw new Exception("Class requiring too many tables: '$sClass'. The structure of the class ($sClass) would require a query with more than 61 JOINS (MySQL's limitation).");
|
||||
}
|
||||
$iCount++;
|
||||
}
|
||||
$fDuration = microtime(true) - $fStart;
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$oSearch->SetShowObsoleteData(false);
|
||||
$oSQLQuery = $oSearch->GetSQLQueryStructure(null, false);
|
||||
$sViewName = MetaModel::DBGetView($sClass);
|
||||
if (strlen($sViewName) > 64)
|
||||
{
|
||||
throw new Exception("Class name too long for class: '$sClass'. The name of the corresponding view ($sViewName) would exceed MySQL's limit for the name of a table (64 characters).");
|
||||
}
|
||||
$sTableName = MetaModel::DBGetTable($sClass);
|
||||
if (strlen($sTableName) > 64)
|
||||
{
|
||||
throw new Exception("Table name too long for class: '$sClass'. The name of the corresponding MySQL table ($sTableName) would exceed MySQL's limit for the name of a table (64 characters).");
|
||||
}
|
||||
$iTableCount = $oSQLQuery->CountTables();
|
||||
if ($iTableCount > 61)
|
||||
{
|
||||
throw new Exception("Class requiring too many tables: '$sClass'. The structure of the class ($sClass) would require a query with more than 61 JOINS (MySQL's limitation).");
|
||||
}
|
||||
$iCount++;
|
||||
}
|
||||
$fDuration = microtime(true) - $fStart;
|
||||
|
||||
return sprintf("Checked %d classes in %.1f ms. No error found.\n", $iCount, $fDuration*1000.0);
|
||||
}
|
||||
return sprintf("Checked %d classes in %.1f ms. No error found.\n", $iCount, $fDuration*1000.0);
|
||||
}
|
||||
} // End of class
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator;
|
||||
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
|
||||
@@ -269,16 +271,16 @@ class InstallationFileService {
|
||||
foreach($this->GetAutoSelectModules() as $sModuleId => $aModule)
|
||||
{
|
||||
try {
|
||||
$bSelected = false;
|
||||
SetupInfo::SetSelectedModules($this->aSelectedModules);
|
||||
eval('$bSelected = ('.$aModule['auto_select'].');');
|
||||
$bSelected = PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($aModule['auto_select']);
|
||||
if ($bSelected)
|
||||
{
|
||||
// Modules in data/production-modules/ are considered as mandatory and always installed
|
||||
$this->aSelectedModules[$sModuleId] = true;
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
catch (ModuleFileReaderException $e) {
|
||||
//logged already
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator;
|
||||
|
||||
require_once(APPROOT.'setup/setuputils.class.inc.php');
|
||||
require_once(APPROOT.'setup/parameters.class.inc.php');
|
||||
@@ -90,7 +91,7 @@ class WizStepWelcome extends WizardStep
|
||||
|
||||
$oPage->add("<!--[if lt IE 11]><div id=\"old_ie\"></div><![endif]-->");
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
if ($('#old_ie').length > 0)
|
||||
{
|
||||
alert("Internet Explorer version 10 or older is NOT supported! (Check that IE is not running in compatibility mode)");
|
||||
@@ -144,7 +145,7 @@ EOF
|
||||
$sH2Class = 'text-valid';
|
||||
}
|
||||
$oPage->add(
|
||||
<<<HTML
|
||||
<<<HTML
|
||||
<h2 class="message">Prerequisites validation: <span class="$sH2Class">$sTitle</span></h2>
|
||||
<div id="details" $sStyle>
|
||||
HTML
|
||||
@@ -271,12 +272,12 @@ class WizStepInstallOrUpgrade extends WizardStep
|
||||
}
|
||||
$oPage->add('<div class="setup-content-title">What do you want to do?</div>');
|
||||
$sChecked = ($sInstallMode == 'install') ? ' checked ' : '';
|
||||
$oPage->p('<input id="radio_install" type="radio" name="install_mode" value="install" '.$sChecked.'/><label for="radio_install"> Install a new '.ITOP_APPLICATION.'</label>');
|
||||
$oPage->p('<input id="radio_install" type="radio" name="install_mode" value="install" '.$sChecked.'/><label for="radio_install"> Install a new '.ITOP_APPLICATION.'</label>');
|
||||
$sChecked = ($sInstallMode == 'upgrade') ? ' checked ' : '';
|
||||
$sDisabled = (($sInstallMode == 'install') && (empty($sPreviousVersionDir))) ? ' disabled' : '';
|
||||
$oPage->p('<input id="radio_update" type="radio" name="install_mode" value="upgrade" '.$sChecked.$sDisabled.'/><label for="radio_update"> Upgrade an existing '.ITOP_APPLICATION.' instance</label>');
|
||||
$oPage->p('<input id="radio_update" type="radio" name="install_mode" value="upgrade" '.$sChecked.$sDisabled.'/><label for="radio_update"> Upgrade an existing '.ITOP_APPLICATION.' instance</label>');
|
||||
|
||||
$sUpgradeDir = utils::HtmlEntities($sPreviousVersionDir);
|
||||
$sUpgradeDir = utils::HtmlEntities($sPreviousVersionDir);
|
||||
$oPage->add(<<<HTML
|
||||
<div id="upgrade_info"'.$sUpgradeInfoStyle.'>
|
||||
<div class="setup-disk-location--input--container">Location on the disk:<input id="previous_version_dir_display" type="text" value="$sUpgradeDir" class="ibo-input" disabled>
|
||||
@@ -319,7 +320,7 @@ HTML
|
||||
$oPage->add('<input type="hidden" id="authent_token" value="'.$sAuthentToken.'"/>');
|
||||
//$oPage->add('</fieldset>');
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
<<<JS
|
||||
$("#radio_update").on('change', function() { if (this.checked ) { $('#upgrade_info').show(); WizardUpdateButtons(); } else { $('#upgrade_info').hide(); } });
|
||||
$("#radio_install").on('change', function() { if (this.checked ) { $('#upgrade_info').hide(); WizardUpdateButtons(); } else { $('#upgrade_info').show(); } });
|
||||
$("#db_backup_path").on('change keyup', function() { WizardAsyncAction('check_backup', { db_backup_path: $('#db_backup_path').val() }); });
|
||||
@@ -350,12 +351,12 @@ JS
|
||||
$("#db_pwd").trigger('change'); // Forces check of the DB connection
|
||||
EOF
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'check_db':
|
||||
SetupUtils:: AsyncCheckDB($oPage, $aParameters);
|
||||
break;
|
||||
SetupUtils:: AsyncCheckDB($oPage, $aParameters);
|
||||
break;
|
||||
|
||||
case 'check_backup':
|
||||
$sDBBackupPath = $aParameters['db_backup_path'];
|
||||
@@ -372,9 +373,9 @@ EOF
|
||||
<<<EOF
|
||||
$("#backup_info").html('');
|
||||
EOF
|
||||
);
|
||||
}
|
||||
break;
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,7 +386,7 @@ EOF
|
||||
public function JSCanMoveForward()
|
||||
{
|
||||
return
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
if ($("#radio_install").prop("checked"))
|
||||
{
|
||||
ValidateField("db_name", false);
|
||||
@@ -403,7 +404,7 @@ EOF
|
||||
return bRet;
|
||||
}
|
||||
EOF
|
||||
;
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -436,19 +437,19 @@ class WizStepDetectedInfo extends WizardStep
|
||||
switch ($sUpgradeType)
|
||||
{
|
||||
case 'keep-previous':
|
||||
$sSourceDir = utils::ReadParam('relative_source_dir', '', false, 'raw_data');
|
||||
$this->oWizard->SetParameter('source_dir', $this->oWizard->GetParameter('previous_version_dir').'/'.$sSourceDir);
|
||||
$this->oWizard->SetParameter('datamodel_version', utils::ReadParam('datamodel_previous_version', '', false, 'raw_data'));
|
||||
break;
|
||||
$sSourceDir = utils::ReadParam('relative_source_dir', '', false, 'raw_data');
|
||||
$this->oWizard->SetParameter('source_dir', $this->oWizard->GetParameter('previous_version_dir').'/'.$sSourceDir);
|
||||
$this->oWizard->SetParameter('datamodel_version', utils::ReadParam('datamodel_previous_version', '', false, 'raw_data'));
|
||||
break;
|
||||
|
||||
case 'use-compatible':
|
||||
$sDataModelPath = utils::ReadParam('datamodel_path', '', false, 'raw_data');
|
||||
$this->oWizard->SetParameter('source_dir', $sDataModelPath);
|
||||
$this->oWizard->SaveParameter('datamodel_version', '');
|
||||
break;
|
||||
$sDataModelPath = utils::ReadParam('datamodel_path', '', false, 'raw_data');
|
||||
$this->oWizard->SetParameter('source_dir', $sDataModelPath);
|
||||
$this->oWizard->SaveParameter('datamodel_version', '');
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing, maybe the user pressed the Back button
|
||||
// Do nothing, maybe the user pressed the Back button
|
||||
}
|
||||
if ($bDisplayLicense)
|
||||
{
|
||||
@@ -469,7 +470,7 @@ class WizStepDetectedInfo extends WizardStep
|
||||
public function Display(WebPage $oPage)
|
||||
{
|
||||
$oPage->add_style(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
#changes_summary {
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
@@ -604,9 +605,9 @@ EOF
|
||||
// No changes detected... or no way to tell because of the lack of a manifest or previous source dir
|
||||
// Use the "compatible" datamodel as-is.
|
||||
$sCompatibleDMDirToDisplay = utils::HtmlEntities($sCompatibleDMDir);
|
||||
$sUpgradeDMVersionToDisplay = utils::HtmlEntities($sUpgradeDMVersion);
|
||||
$sUpgradeDMVersionToDisplay = utils::HtmlEntities($sUpgradeDMVersion);
|
||||
$oPage->add(
|
||||
<<<HTML
|
||||
<<<HTML
|
||||
<div class="message message-valid">The datamodel will be upgraded from version $sInstalledDataModelVersion to version $sUpgradeDMVersion.</div>
|
||||
<input type="hidden" name="upgrade_type" value="use-compatible">
|
||||
<input type="hidden" name="datamodel_path" value="$sCompatibleDMDirToDisplay">
|
||||
@@ -617,7 +618,7 @@ HTML
|
||||
}
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
$("#changes_summary .title").on('click', function() { $(this).parent().toggleClass('closed'); } );
|
||||
$('input[name=upgrade_type]').on('click change', function() { WizardUpdateButtons(); });
|
||||
EOF
|
||||
@@ -650,13 +651,13 @@ EOF
|
||||
public function JSCanMoveForward()
|
||||
{
|
||||
return
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
if ($("#radio_upgrade_keep").length == 0) return true;
|
||||
|
||||
bRet = ($('input[name=upgrade_type]:checked').length > 0);
|
||||
return bRet;
|
||||
EOF
|
||||
;
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,55 +696,55 @@ class WizStepLicense extends WizardStep
|
||||
return (($sMode === 'install') && SetupUtils::IsConnectableToITopHub($aModules));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
*/
|
||||
public function Display(WebPage $oPage)
|
||||
{
|
||||
$aLicenses = SetupUtils::GetLicenses();
|
||||
$oPage->add_style(
|
||||
<<<CSS
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
*/
|
||||
public function Display(WebPage $oPage)
|
||||
{
|
||||
$aLicenses = SetupUtils::GetLicenses();
|
||||
$oPage->add_style(
|
||||
<<<CSS
|
||||
fieldset ul {
|
||||
max-height: min(30em, 40vh); /* Allow usage of the UI up to 150% zoom */
|
||||
overflow: auto;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
);
|
||||
|
||||
$oPage->add('<h2>Licenses agreements for the components of '.ITOP_APPLICATION.'</h2>');
|
||||
$oPage->add_style('div a.no-arrow { background:transparent; padding-left:0;}');
|
||||
$oPage->add_style('.toggle { cursor:pointer; text-decoration:underline; color:#1C94C4; }');
|
||||
$oPage->add('<fieldset>');
|
||||
$oPage->add('<legend>Components of '.ITOP_APPLICATION.'</legend>');
|
||||
$oPage->add('<ul id="ibo-setup-licenses--components-list">');
|
||||
$index = 0;
|
||||
foreach ($aLicenses as $oLicense) {
|
||||
$oPage->add('<li><b>'.$oLicense->product.'</b>, © '.$oLicense->author.' is licensed under the <b>'.$oLicense->license_type.' license</b>. (<span class="toggle" id="toggle_'.$index.'">Details</span>)');
|
||||
$oPage->add('<div id="license_'.$index.'" class="license_text ibo-is-html-content" style="display:none;overflow:auto;max-height:10em;font-size:12px;border:1px #696969 solid;margin-bottom:1em; margin-top:0.5em;padding:0.5em;"><pre>'.$oLicense->text.'</pre></div>');
|
||||
$oPage->add_ready_script('$(".license_text a").attr("target", "_blank").addClass("no-arrow");');
|
||||
$oPage->add_ready_script('$("#toggle_'.$index.'").on("click", function() { $("#license_'.$index.'").toggle(); } );');
|
||||
$index++;
|
||||
}
|
||||
$oPage->add('</ul>');
|
||||
$oPage->add('</fieldset>');
|
||||
$sChecked = ($this->oWizard->GetParameter('accept_license', 'no') == 'yes') ? ' checked ' : '';
|
||||
$oPage->add('<div class="setup-accept-licenses"><input class="check_select" type="checkbox" name="accept_license" id="accept" value="yes" '.$sChecked.'><label for="accept">I accept the terms of the licenses of the '.count($aLicenses).' components mentioned above.</label></div>');
|
||||
if ($this->NeedsGdprConsent()) {
|
||||
$oPage->add('<br>');
|
||||
$oPage->add('<fieldset>');
|
||||
$oPage->add('<legend>European General Data Protection Regulation</legend>');
|
||||
$oPage->add('<div class="ibo-setup-licenses--components-list">'.ITOP_APPLICATION.' software is compliant with the processing of personal data according to the European General Data Protection Regulation (GDPR).<p></p>
|
||||
$oPage->add('<h2>Licenses agreements for the components of '.ITOP_APPLICATION.'</h2>');
|
||||
$oPage->add_style('div a.no-arrow { background:transparent; padding-left:0;}');
|
||||
$oPage->add_style('.toggle { cursor:pointer; text-decoration:underline; color:#1C94C4; }');
|
||||
$oPage->add('<fieldset>');
|
||||
$oPage->add('<legend>Components of '.ITOP_APPLICATION.'</legend>');
|
||||
$oPage->add('<ul id="ibo-setup-licenses--components-list">');
|
||||
$index = 0;
|
||||
foreach ($aLicenses as $oLicense) {
|
||||
$oPage->add('<li><b>'.$oLicense->product.'</b>, © '.$oLicense->author.' is licensed under the <b>'.$oLicense->license_type.' license</b>. (<span class="toggle" id="toggle_'.$index.'">Details</span>)');
|
||||
$oPage->add('<div id="license_'.$index.'" class="license_text ibo-is-html-content" style="display:none;overflow:auto;max-height:10em;font-size:12px;border:1px #696969 solid;margin-bottom:1em; margin-top:0.5em;padding:0.5em;"><pre>'.$oLicense->text.'</pre></div>');
|
||||
$oPage->add_ready_script('$(".license_text a").attr("target", "_blank").addClass("no-arrow");');
|
||||
$oPage->add_ready_script('$("#toggle_'.$index.'").on("click", function() { $("#license_'.$index.'").toggle(); } );');
|
||||
$index++;
|
||||
}
|
||||
$oPage->add('</ul>');
|
||||
$oPage->add('</fieldset>');
|
||||
$sChecked = ($this->oWizard->GetParameter('accept_license', 'no') == 'yes') ? ' checked ' : '';
|
||||
$oPage->add('<div class="setup-accept-licenses"><input class="check_select" type="checkbox" name="accept_license" id="accept" value="yes" '.$sChecked.'><label for="accept">I accept the terms of the licenses of the '.count($aLicenses).' components mentioned above.</label></div>');
|
||||
if ($this->NeedsGdprConsent()) {
|
||||
$oPage->add('<br>');
|
||||
$oPage->add('<fieldset>');
|
||||
$oPage->add('<legend>European General Data Protection Regulation</legend>');
|
||||
$oPage->add('<div class="ibo-setup-licenses--components-list">'.ITOP_APPLICATION.' software is compliant with the processing of personal data according to the European General Data Protection Regulation (GDPR).<p></p>
|
||||
By installing '.ITOP_APPLICATION.' you agree that some information will be collected by Combodo to help you manage your instances and for statistical purposes.
|
||||
This data remains anonymous until it is associated to a user account on iTop Hub.</p>
|
||||
<p>List of collected data available in our <a target="_blank" href="https://www.itophub.io/page/data-privacy">Data privacy section.</a></p><br></div>');
|
||||
$oPage->add('<input type="checkbox" class="check_select" id="rgpd_consent">');
|
||||
$oPage->add('<label for="rgpd_consent"> I accept the processing of my personal data</label>');
|
||||
$oPage->add('</fieldset>');
|
||||
}
|
||||
$oPage->add_ready_script('$(".check_select").on("click change", function() { WizardUpdateButtons(); });');
|
||||
$oPage->add('<input type="checkbox" class="check_select" id="rgpd_consent">');
|
||||
$oPage->add('<label for="rgpd_consent"> I accept the processing of my personal data</label>');
|
||||
$oPage->add('</fieldset>');
|
||||
}
|
||||
$oPage->add_ready_script('$(".check_select").on("click change", function() { WizardUpdateButtons(); });');
|
||||
|
||||
$oPage->add_script(
|
||||
<<<JS
|
||||
$oPage->add_script(
|
||||
<<<JS
|
||||
function isRgpdConsentOk(){
|
||||
let eRgpdConsent = $("#rgpd_consent");
|
||||
if(eRgpdConsent.length){
|
||||
@@ -754,7 +755,7 @@ This data remains anonymous until it is associated to a user account on iTop Hub
|
||||
return true;
|
||||
}
|
||||
JS
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -850,8 +851,8 @@ class WizStepDBParams extends WizardStep
|
||||
switch($sCode)
|
||||
{
|
||||
case 'check_db':
|
||||
SetupUtils:: AsyncCheckDB($oPage, $aParameters);
|
||||
break;
|
||||
SetupUtils:: AsyncCheckDB($oPage, $aParameters);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -862,7 +863,7 @@ class WizStepDBParams extends WizardStep
|
||||
public function JSCanMoveForward()
|
||||
{
|
||||
return
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
if ($("#wiz_form").data("db_connection") === "error") return false;
|
||||
|
||||
var bRet = true;
|
||||
@@ -872,7 +873,7 @@ class WizStepDBParams extends WizardStep
|
||||
|
||||
return bRet;
|
||||
EOF
|
||||
;
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,7 +938,7 @@ EOF
|
||||
public function JSCanMoveForward()
|
||||
{
|
||||
return
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
bRet = ($('#admin_user').val() != '');
|
||||
if (!bRet)
|
||||
{
|
||||
@@ -1107,10 +1108,10 @@ EOF
|
||||
default:
|
||||
case CheckResult::ERROR:
|
||||
case CheckResult::WARNING:
|
||||
$sStatus = 'ko';
|
||||
$sErrorExplanation = $oCheck->sLabel;
|
||||
$sMessage = json_encode('<div class="message message-error">'.$sErrorExplanation.'</div>');
|
||||
break;
|
||||
$sStatus = 'ko';
|
||||
$sErrorExplanation = $oCheck->sLabel;
|
||||
$sMessage = json_encode('<div class="message message-error">'.$sErrorExplanation.'</div>');
|
||||
break;
|
||||
}
|
||||
|
||||
if ($oCheck->iSeverity !== CheckResult::TRACE) {
|
||||
@@ -1134,7 +1135,7 @@ JS
|
||||
public function JSCanMoveForward()
|
||||
{
|
||||
return
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
bRet = ($('#application_url').val() != '');
|
||||
if (!bRet)
|
||||
{
|
||||
@@ -1156,7 +1157,7 @@ JS
|
||||
}
|
||||
return bRet;
|
||||
EOF
|
||||
;
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1261,7 +1262,7 @@ EOF
|
||||
JS
|
||||
);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1272,7 +1273,7 @@ JS
|
||||
public function JSCanMoveForward()
|
||||
{
|
||||
return
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
bRet = ($('#application_url').val() != '');
|
||||
if (!bRet)
|
||||
{
|
||||
@@ -1294,7 +1295,7 @@ JS
|
||||
}
|
||||
return bRet;
|
||||
EOF
|
||||
;
|
||||
;
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -1481,7 +1482,7 @@ class WizStepModulesChoice extends WizardStep
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
function CheckChoice(sChoiceId)
|
||||
{
|
||||
var oElement = $('#'+sChoiceId);
|
||||
@@ -1530,7 +1531,7 @@ function CheckChoice(sChoiceId)
|
||||
EOF
|
||||
);
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
$('.wiz-choice').on('change', function() { CheckChoice($(this).attr('id')); } );
|
||||
$('.wiz-choice').trigger('change');
|
||||
EOF
|
||||
@@ -1786,11 +1787,11 @@ EOF
|
||||
if (isset($aInfo['auto_select'])) {
|
||||
// Check the module selection
|
||||
try {
|
||||
$bSelected = false;
|
||||
SetupInfo::SetSelectedModules($aModules);
|
||||
eval('$bSelected = ('.$aInfo['auto_select'].');');
|
||||
$bSelected = PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($aInfo['auto_select']);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
catch (ModuleFileReaderException $e) {
|
||||
//logged already
|
||||
$bSelected = false;
|
||||
}
|
||||
}
|
||||
@@ -1825,7 +1826,7 @@ EOF
|
||||
$sChoiceName = $sChoiceId;
|
||||
}
|
||||
if ( (isset($aChoice['mandatory']) && $aChoice['mandatory']) ||
|
||||
(isset($aSelectedChoices[$sChoiceName]) && ($aSelectedChoices[$sChoiceName] == $sChoiceId)) )
|
||||
(isset($aSelectedChoices[$sChoiceName]) && ($aSelectedChoices[$sChoiceName] == $sChoiceId)) )
|
||||
{
|
||||
$sDisplayChoices .= '<li>'.$aChoice['title'].'</li>';
|
||||
if ($aSelectedExtensions !== null)
|
||||
@@ -1864,20 +1865,19 @@ EOF
|
||||
{
|
||||
try
|
||||
{
|
||||
$bSelected = false;
|
||||
SetupInfo::SetSelectedModules($aModules);
|
||||
eval('$bSelected = ('.$aModule['auto_select'].');');
|
||||
$bSelected = PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($aModule['auto_select']);
|
||||
if ($bSelected)
|
||||
{
|
||||
$aModules[$sModuleId] = true; // store the Id of the selected module
|
||||
$sDisplayChoices .= '<li>'.$aModule['label'].' (auto_select)</li>';
|
||||
$bModuleAdded = true;
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
catch(ModuleFileReaderException $e)
|
||||
{
|
||||
//logged already
|
||||
$sDisplayChoices .= '<li><b>Warning: auto_select failed with exception ('.$e->getMessage().') for module "'.$sModuleId.'"</b></li>';
|
||||
$bSelected = false;
|
||||
}
|
||||
if ($bSelected)
|
||||
{
|
||||
$aModules[$sModuleId] = true; // store the Id of the selected module
|
||||
$sDisplayChoices .= '<li>'.$aModule['label'].' (auto_select)</li>';
|
||||
$bModuleAdded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1894,11 +1894,11 @@ EOF
|
||||
{
|
||||
case 'start_install':
|
||||
case 'start_upgrade':
|
||||
$index = 0;
|
||||
break;
|
||||
$index = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
$index = (integer)$this->sCurrentState;
|
||||
$index = (integer)$this->sCurrentState;
|
||||
}
|
||||
return $index;
|
||||
}
|
||||
@@ -1925,10 +1925,10 @@ EOF
|
||||
|
||||
// Additional step for the "extensions"
|
||||
$aStepDefinition = array(
|
||||
'title' => 'Extensions',
|
||||
'description' => '<h2>Select additional extensions to install. You can launch the installation again to install new extensions, but you cannot remove already installed extensions.</h2>',
|
||||
'banner' => '/images/icons/icons8-puzzle.svg',
|
||||
'options' => array()
|
||||
'title' => 'Extensions',
|
||||
'description' => '<h2>Select additional extensions to install. You can launch the installation again to install new extensions, but you cannot remove already installed extensions.</h2>',
|
||||
'banner' => '/images/icons/icons8-puzzle.svg',
|
||||
'options' => array()
|
||||
);
|
||||
|
||||
foreach($this->oExtensionsMap->GetAllExtensions() as $oExtension)
|
||||
@@ -1936,14 +1936,14 @@ EOF
|
||||
if (($oExtension->sSource !== iTopExtension::SOURCE_WIZARD) && ($oExtension->bVisible) && (count($oExtension->aMissingDependencies) == 0))
|
||||
{
|
||||
$aStepDefinition['options'][] = array(
|
||||
'extension_code' => $oExtension->sCode,
|
||||
'title' => $oExtension->sLabel,
|
||||
'description' => $oExtension->sDescription,
|
||||
'more_info' => $oExtension->sMoreInfoUrl,
|
||||
'default' => true, // by default offer to install all modules
|
||||
'modules' => $oExtension->aModules,
|
||||
'mandatory' => $oExtension->bMandatory || ($oExtension->sSource === iTopExtension::SOURCE_REMOTE),
|
||||
'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource),
|
||||
'extension_code' => $oExtension->sCode,
|
||||
'title' => $oExtension->sLabel,
|
||||
'description' => $oExtension->sDescription,
|
||||
'more_info' => $oExtension->sMoreInfoUrl,
|
||||
'default' => true, // by default offer to install all modules
|
||||
'modules' => $oExtension->aModules,
|
||||
'mandatory' => $oExtension->bMandatory || ($oExtension->sSource === iTopExtension::SOURCE_REMOTE),
|
||||
'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1958,24 +1958,24 @@ EOF
|
||||
{
|
||||
// No wizard configuration provided, build a standard one with just one big list
|
||||
$aStepDefinition = array(
|
||||
'title' => 'Modules Selection',
|
||||
'description' => '<h2>Select the modules to install. You can launch the installation again to install new modules, but you cannot remove already installed modules.</h2>',
|
||||
'banner' => '/images/icons/icons8-apps-tab.svg',
|
||||
'options' => array()
|
||||
'title' => 'Modules Selection',
|
||||
'description' => '<h2>Select the modules to install. You can launch the installation again to install new modules, but you cannot remove already installed modules.</h2>',
|
||||
'banner' => '/images/icons/icons8-apps-tab.svg',
|
||||
'options' => array()
|
||||
);
|
||||
foreach($this->oExtensionsMap->GetAllExtensions() as $oExtension)
|
||||
{
|
||||
if (($oExtension->bVisible) && (count($oExtension->aMissingDependencies) == 0))
|
||||
{
|
||||
$aStepDefinition['options'][] = array(
|
||||
'extension_code' => $oExtension->sCode,
|
||||
'title' => $oExtension->sLabel,
|
||||
'description' => $oExtension->sDescription,
|
||||
'more_info' => $oExtension->sMoreInfoUrl,
|
||||
'default' => true, // by default offer to install all modules
|
||||
'modules' => $oExtension->aModules,
|
||||
'mandatory' => $oExtension->bMandatory || ($oExtension->sSource !== iTopExtension::SOURCE_REMOTE),
|
||||
'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource),
|
||||
'extension_code' => $oExtension->sCode,
|
||||
'title' => $oExtension->sLabel,
|
||||
'description' => $oExtension->sDescription,
|
||||
'more_info' => $oExtension->sMoreInfoUrl,
|
||||
'default' => true, // by default offer to install all modules
|
||||
'modules' => $oExtension->aModules,
|
||||
'mandatory' => $oExtension->bMandatory || ($oExtension->sSource !== iTopExtension::SOURCE_REMOTE),
|
||||
'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1996,17 +1996,17 @@ EOF
|
||||
switch($sSource)
|
||||
{
|
||||
case iTopExtension::SOURCE_MANUAL:
|
||||
$sResult = 'Local extensions folder';
|
||||
$sDecorationClass = 'fas fa-folder';
|
||||
break;
|
||||
$sResult = 'Local extensions folder';
|
||||
$sDecorationClass = 'fas fa-folder';
|
||||
break;
|
||||
|
||||
case iTopExtension::SOURCE_REMOTE:
|
||||
$sResult = (ITOP_APPLICATION == 'iTop') ? 'iTop Hub' : 'ITSM Designer';
|
||||
$sDecorationClass = (ITOP_APPLICATION == 'iTop') ? 'fc fc-chameleon-icon' : 'fa pencil-ruler';
|
||||
break;
|
||||
$sResult = (ITOP_APPLICATION == 'iTop') ? 'iTop Hub' : 'ITSM Designer';
|
||||
$sDecorationClass = (ITOP_APPLICATION == 'iTop') ? 'fc fc-chameleon-icon' : 'fa pencil-ruler';
|
||||
break;
|
||||
|
||||
default:
|
||||
$sResult = '';
|
||||
$sResult = '';
|
||||
}
|
||||
if ($sResult == '')
|
||||
{
|
||||
@@ -2591,10 +2591,10 @@ class WizStepDone extends WizardStep
|
||||
$oProductionEnv->InitDataModel($oConfig, true);
|
||||
$sIframeUrl = $oConfig->GetModuleSetting('itop-hub-connector', 'setup_url', '');
|
||||
|
||||
$sSetupTokenFile = APPROOT.'data/.setup';
|
||||
$sSetupToken = bin2hex(random_bytes(12));
|
||||
file_put_contents($sSetupTokenFile, $sSetupToken);
|
||||
$sIframeUrl.= "&setup_token=$sSetupToken";
|
||||
$sSetupTokenFile = APPROOT.'data/.setup';
|
||||
$sSetupToken = bin2hex(random_bytes(12));
|
||||
file_put_contents($sSetupTokenFile, $sSetupToken);
|
||||
$sIframeUrl.= "&setup_token=$sSetupToken";
|
||||
|
||||
if ($sIframeUrl != '')
|
||||
{
|
||||
|
||||
9
sources/PhpParser/Evaluation/AbstractExprEvaluator.php
Normal file
9
sources/PhpParser/Evaluation/AbstractExprEvaluator.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
abstract class AbstractExprEvaluator implements iExprEvaluator {
|
||||
public function GetHandledExpressionTypes(): ?array {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
28
sources/PhpParser/Evaluation/ArrayDimFetchEvaluator.php
Normal file
28
sources/PhpParser/Evaluation/ArrayDimFetchEvaluator.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
|
||||
class ArrayDimFetchEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return ArrayDimFetch::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var ArrayDimFetch $oExpr */
|
||||
|
||||
$var = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->var);
|
||||
if (is_null($var)){
|
||||
return null;
|
||||
}
|
||||
|
||||
$dim = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->dim);
|
||||
if (is_null($var)){
|
||||
return $dim;
|
||||
}
|
||||
|
||||
return $var[$dim] ?? null;
|
||||
}
|
||||
}
|
||||
48
sources/PhpParser/Evaluation/ArrayEvaluator.php
Normal file
48
sources/PhpParser/Evaluation/ArrayEvaluator.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use ModuleFileReaderException;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Scalar\Int_;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
|
||||
class ArrayEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Array_::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var Array_ $oExpr */
|
||||
$iIndex=0;
|
||||
|
||||
$aModuleInformation=[];
|
||||
/** @var \PhpParser\Node\Expr\ArrayItem $oValue */
|
||||
foreach ($oExpr->items as $oArrayItem){
|
||||
if ($oArrayItem->key instanceof Int_||$oArrayItem->key instanceof String_||$oArrayItem->key instanceof ConstFetch) {
|
||||
//dictionnary
|
||||
$sKey = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oArrayItem->key);
|
||||
if (is_null($sKey)){
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
//array
|
||||
$sKey = $iIndex++;
|
||||
}
|
||||
|
||||
try {
|
||||
$oValue = $oArrayItem->value;
|
||||
$oEvaluatuedValue = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oValue);
|
||||
$aModuleInformation[$sKey]=$oEvaluatuedValue;
|
||||
} catch(ModuleFileReaderException $e){
|
||||
//required to support legacy below dump dependency
|
||||
//'dependencies' => ['itop-config-mgmt/2.0.0'||'itop-structure/3.0.0']
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $aModuleInformation;
|
||||
}
|
||||
}
|
||||
18
sources/PhpParser/Evaluation/BinaryOpEvaluator.php
Normal file
18
sources/PhpParser/Evaluation/BinaryOpEvaluator.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\BinaryOp;
|
||||
|
||||
abstract class BinaryOpEvaluator extends AbstractExprEvaluator {
|
||||
abstract function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed;
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var BinaryOp $oExpr */
|
||||
|
||||
return $this->EvaluateBinaryOperation(
|
||||
PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->left),
|
||||
PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->right));
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/BitwiseAndEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/BitwiseAndEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\BitwiseAnd;
|
||||
|
||||
class BitwiseAndEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return BitwiseAnd::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left & $right;
|
||||
}
|
||||
}
|
||||
18
sources/PhpParser/Evaluation/BitwiseNotEvaluator.php
Normal file
18
sources/PhpParser/Evaluation/BitwiseNotEvaluator.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\BitwiseNot;
|
||||
|
||||
class BitwiseNotEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return BitwiseNot::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var BitwiseNot $oExpr */
|
||||
|
||||
return ~ PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->expr);
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/BitwiseOrEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/BitwiseOrEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\BitwiseOr;
|
||||
|
||||
class BitwiseOrEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return BitwiseOr::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left | $right;
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/BitwiseXorEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/BitwiseXorEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\BitwiseXor;
|
||||
|
||||
class BitwiseXorEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return BitwiseXor::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left ^ $right;
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/BooleanAndEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/BooleanAndEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\BooleanAnd;
|
||||
|
||||
class BooleanAndEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return BooleanAnd::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left && $right;
|
||||
}
|
||||
}
|
||||
18
sources/PhpParser/Evaluation/BooleanNotEvaluator.php
Normal file
18
sources/PhpParser/Evaluation/BooleanNotEvaluator.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\BooleanNot;
|
||||
|
||||
class BooleanNotEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return BooleanNot::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var BooleanNot $oExpr */
|
||||
|
||||
return ! PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->expr);
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/BooleanOrEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/BooleanOrEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\BooleanOr;
|
||||
|
||||
class BooleanOrEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return BooleanOr::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left || $right;
|
||||
}
|
||||
}
|
||||
59
sources/PhpParser/Evaluation/CastEvaluator.php
Normal file
59
sources/PhpParser/Evaluation/CastEvaluator.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
|
||||
class CastEvaluator implements iExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetHandledExpressionTypes(): ?array {
|
||||
return [
|
||||
Cast\Array_::class,
|
||||
Cast\Bool_::class,
|
||||
Cast\Double::class,
|
||||
Cast\Int_::class,
|
||||
Cast\Object_::class,
|
||||
Cast\String_::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
$oSubExpr = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->expr);
|
||||
switch (get_class($oExpr)){
|
||||
case Cast\Array_::class:
|
||||
return (array) $oSubExpr;
|
||||
|
||||
case Cast\Bool_::class:
|
||||
return (bool) $oSubExpr;
|
||||
|
||||
case Cast\Double::class:
|
||||
/** @var Cast\Double $oExpr */
|
||||
switch ($oExpr->getAttribute("kind")){
|
||||
case Cast\Double::KIND_DOUBLE:
|
||||
return (double) $oSubExpr;
|
||||
|
||||
case Cast\Double::KIND_FLOAT:
|
||||
case Cast\Double::KIND_REAL:
|
||||
return (float) $oSubExpr;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Cast\Int_::class:
|
||||
return (int) $oSubExpr;
|
||||
|
||||
case Cast\Object_::class:
|
||||
return (object) $oSubExpr;
|
||||
|
||||
case Cast\String_::class:
|
||||
return (string) $oSubExpr;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
35
sources/PhpParser/Evaluation/ClassConstFetchEvaluator.php
Normal file
35
sources/PhpParser/Evaluation/ClassConstFetchEvaluator.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
|
||||
class ClassConstFetchEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return ClassConstFetch::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var ClassConstFetch $oExpr */
|
||||
|
||||
$sClassName = $oExpr->class->name;
|
||||
$sProperty = $oExpr->name->name;
|
||||
|
||||
if ('class' === $sProperty){
|
||||
return $sClassName;
|
||||
}
|
||||
|
||||
if (class_exists($sClassName)){
|
||||
$class = new \ReflectionClass($sClassName);
|
||||
if (array_key_exists($sProperty, $class->getConstants())) {
|
||||
$oReflectionConstant = $class->getReflectionConstant($sProperty);
|
||||
if ($oReflectionConstant->isPublic()){
|
||||
return $class->getConstant($sProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
23
sources/PhpParser/Evaluation/CoalesceEvaluator.php
Normal file
23
sources/PhpParser/Evaluation/CoalesceEvaluator.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\BinaryOp\Coalesce;
|
||||
|
||||
class CoalesceEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Coalesce::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var Coalesce $oExpr */
|
||||
|
||||
$oLeftEval = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->left);
|
||||
if (! is_null($oLeftEval)) {
|
||||
return $oLeftEval;
|
||||
}
|
||||
|
||||
return PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->right);
|
||||
}
|
||||
}
|
||||
28
sources/PhpParser/Evaluation/ConcatEvaluator.php
Normal file
28
sources/PhpParser/Evaluation/ConcatEvaluator.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\Concat;
|
||||
|
||||
class ConcatEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Concat::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
if (is_null($left) && is_null($right)){
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_null($left)){
|
||||
return $right;
|
||||
}
|
||||
|
||||
if (is_null($right)){
|
||||
return $left;
|
||||
}
|
||||
|
||||
return "$left" . "$right";
|
||||
}
|
||||
}
|
||||
21
sources/PhpParser/Evaluation/ConstFetchEvaluator.php
Normal file
21
sources/PhpParser/Evaluation/ConstFetchEvaluator.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
|
||||
class ConstFetchEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return ConstFetch::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var ConstFetch $oExpr */
|
||||
if (defined($oExpr->name)){
|
||||
return constant($oExpr->name);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/EqualEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/EqualEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\Equal;
|
||||
|
||||
class EqualEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Equal::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left == $right;
|
||||
}
|
||||
}
|
||||
44
sources/PhpParser/Evaluation/FuncCallEvaluator.php
Normal file
44
sources/PhpParser/Evaluation/FuncCallEvaluator.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use ModuleFileReaderException;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use ReflectionFunction;
|
||||
|
||||
class FuncCallEvaluator extends AbstractExprEvaluator {
|
||||
public const WHITELIST=[
|
||||
"function_exists",
|
||||
"class_exists",
|
||||
"method_exists"
|
||||
];
|
||||
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return FuncCall::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var FuncCall $oExpr */
|
||||
|
||||
if ($oExpr->name instanceof Name){
|
||||
$sFunction = $oExpr->name->name;
|
||||
} else {
|
||||
$sFunction = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name);
|
||||
}
|
||||
if (! in_array($sFunction, self::WHITELIST)){
|
||||
throw new ModuleFileReaderException("FuncCall $sFunction not supported");
|
||||
}
|
||||
|
||||
$aArgs=[];
|
||||
foreach ($oExpr->args as $arg){
|
||||
/** @var \PhpParser\Node\Arg $arg */
|
||||
$aArgs[]=$arg->value->value;
|
||||
}
|
||||
|
||||
$oReflectionFunction = new ReflectionFunction($sFunction);
|
||||
return $oReflectionFunction->invoke(...$aArgs);
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/GreaterEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/GreaterEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\Greater;
|
||||
|
||||
class GreaterEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Greater::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left > $right;
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/GreaterOrEqualEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/GreaterOrEqualEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\GreaterOrEqual;
|
||||
|
||||
class GreaterOrEqualEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return GreaterOrEqual::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left >= $right;
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/IdenticalEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/IdenticalEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\Identical;
|
||||
|
||||
class IdenticalEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Identical::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left === $right;
|
||||
}
|
||||
}
|
||||
30
sources/PhpParser/Evaluation/IssetEvaluator.php
Normal file
30
sources/PhpParser/Evaluation/IssetEvaluator.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\Isset_;
|
||||
|
||||
class IssetEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Isset_::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var Isset_ $oExpr */
|
||||
|
||||
foreach ($oExpr->vars as $oVar){
|
||||
try{
|
||||
$var = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oVar);
|
||||
if (is_null($var)){
|
||||
return false;
|
||||
}
|
||||
} catch (\Throwable $t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
48
sources/PhpParser/Evaluation/MethodCallEvaluator.php
Normal file
48
sources/PhpParser/Evaluation/MethodCallEvaluator.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Identifier;
|
||||
use ReflectionClass;
|
||||
|
||||
class MethodCallEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetHandledExpressionTypes(): ?array {
|
||||
return [MethodCall::class, Expr\NullsafeMethodCall::class];
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
$oVar = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->var);
|
||||
if (is_null($oVar)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$aArgs=[];
|
||||
foreach ($oExpr->args as $arg){
|
||||
/** @var \PhpParser\Node\Arg $arg */
|
||||
$aArgs[]=$arg->value->value;
|
||||
}
|
||||
|
||||
if ($oExpr->name instanceof Identifier){
|
||||
$sName = $oExpr->name->name;
|
||||
} else {
|
||||
$sName = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name);
|
||||
}
|
||||
|
||||
$oReflectionClass = new ReflectionClass(get_class($oVar));
|
||||
try{
|
||||
$oMethod = $oReflectionClass->getMethod($sName);
|
||||
if ($oMethod->isPublic()){
|
||||
return $oMethod->invokeArgs($oVar, $aArgs);
|
||||
}
|
||||
} catch (\ReflectionException $t) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/ModEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/ModEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\Mod;
|
||||
|
||||
class ModEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Mod::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left % $right;
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/MulEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/MulEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\Mul;
|
||||
|
||||
class MulEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Mul::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left * $right;
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/NotEqualEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/NotEqualEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\NotEqual;
|
||||
|
||||
class NotEqualEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return NotEqual::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left != $right;
|
||||
}
|
||||
}
|
||||
121
sources/PhpParser/Evaluation/PhpExpressionEvaluator.php
Normal file
121
sources/PhpParser/Evaluation/PhpExpressionEvaluator.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use ModuleFileParser;
|
||||
use ModuleFileReaderException;
|
||||
use PhpParser\ConstExprEvaluator;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
class PhpExpressionEvaluator {
|
||||
private static PhpExpressionEvaluator $oInstance;
|
||||
|
||||
/** @var iExprEvaluator[] $aPhpParserEvaluators */
|
||||
private static array $aPhpParserEvaluators;
|
||||
private int $iMode=self::LIB_AND_FALLBACK;
|
||||
|
||||
protected function __construct() {
|
||||
}
|
||||
|
||||
const LIB_AND_FALLBACK=1;
|
||||
const LIB_ONLY=2;
|
||||
const ITOP_ALGO=3;
|
||||
public function SetMode($iMode)
|
||||
{
|
||||
$this->iMode =$iMode;
|
||||
}
|
||||
|
||||
final public static function GetInstance(): PhpExpressionEvaluator {
|
||||
if (!isset(static::$oInstance)) {
|
||||
static::$oInstance = new static();
|
||||
static::$aPhpParserEvaluators=[];
|
||||
|
||||
foreach (glob(__DIR__ . "/**Evaluator.php") as $sFile){
|
||||
require_once $sFile;
|
||||
require_once $sFile;
|
||||
$sNamespace = 'Combodo\\iTop\PhpParser\\Evaluation\\';
|
||||
$sClass = $sNamespace. str_replace(".php", "", basename($sFile));
|
||||
$oReflectionClass = new \ReflectionClass($sClass);
|
||||
if ($oReflectionClass->isInstantiable()
|
||||
&& $oReflectionClass->implementsInterface(iExprEvaluator::class)){
|
||||
$oClass = new $sClass;
|
||||
|
||||
if (! is_null($oClass->GetHandledExpressionType())){
|
||||
static::RegisterEvaluator($oClass, $oClass->GetHandledExpressionType());
|
||||
}
|
||||
if (! is_null($oClass->GetHandledExpressionTypes())) {
|
||||
foreach ($oClass->GetHandledExpressionTypes() as $sHandledExpressionType){
|
||||
static::RegisterEvaluator($oClass, $sHandledExpressionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return static::$oInstance;
|
||||
}
|
||||
|
||||
private static function RegisterEvaluator(iExprEvaluator $oClass, string $sHandledExpressionType)
|
||||
{
|
||||
if (array_key_exists($sHandledExpressionType, static::$aPhpParserEvaluators)){
|
||||
throw new \CoreException("Another Evaluator class already deals with $sHandledExpressionType");
|
||||
}
|
||||
static::$aPhpParserEvaluators[$sHandledExpressionType] = $oClass;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?PhpExpressionEvaluator $oInstance): void {
|
||||
static::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
public function EvaluateExpression(Expr $oExpression) : mixed
|
||||
{
|
||||
if ($this->iMode===self::ITOP_ALGO){
|
||||
return $this->EvaluateExpressionLocally($oExpression);
|
||||
}
|
||||
|
||||
if ($this->iMode==self::LIB_ONLY){
|
||||
$oConstExprEvaluator = new ConstExprEvaluator();
|
||||
} else {
|
||||
$oConstExprEvaluator = new ConstExprEvaluator([$this, "EvaluateExpressionLocally"]);
|
||||
}
|
||||
|
||||
return $oConstExprEvaluator->evaluateDirectly($oExpression);
|
||||
}
|
||||
|
||||
public function EvaluateExpressionLocally(Expr $oExpression) : mixed
|
||||
{
|
||||
$sClass = get_class($oExpression);
|
||||
$oPhpParserEvaluator = static::$aPhpParserEvaluators[$sClass] ?? null;
|
||||
if (is_null($oPhpParserEvaluator)){
|
||||
return $oExpression->value;
|
||||
}
|
||||
|
||||
return $oPhpParserEvaluator->Evaluate($oExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sBooleanExpr
|
||||
*
|
||||
* @return bool
|
||||
* @throws \ModuleFileReaderException
|
||||
*/
|
||||
public function ParseAndEvaluateBooleanExpression(string $sBooleanExpr) : bool
|
||||
{
|
||||
return $this->ParseAndEvaluateExpression($sBooleanExpr);
|
||||
}
|
||||
|
||||
public function ParseAndEvaluateExpression(string $sExpr) : mixed
|
||||
{
|
||||
$sPhpContent = <<<PHP
|
||||
<?php
|
||||
$sExpr;
|
||||
PHP;
|
||||
try{
|
||||
$aNodes = ModuleFileParser::GetInstance()->ParsePhpCode($sPhpContent);
|
||||
$oExpr = $aNodes[0];
|
||||
return $this->EvaluateExpression($oExpr->expr);
|
||||
} catch (\Throwable $t) {
|
||||
throw new ModuleFileReaderException("Eval of '$sExpr' caused an error:".$t->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
41
sources/PhpParser/Evaluation/PropertyFetchEvaluator.php
Normal file
41
sources/PhpParser/Evaluation/PropertyFetchEvaluator.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Identifier;
|
||||
use ReflectionClass;
|
||||
|
||||
class PropertyFetchEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetHandledExpressionTypes(): ?array {
|
||||
return [PropertyFetch::class, Expr\NullsafePropertyFetch::class];
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
$oVar = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->var);
|
||||
if (is_null($oVar)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($oExpr->name instanceof Identifier){
|
||||
$sName = $oExpr->name->name;
|
||||
} else {
|
||||
$sName = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name);
|
||||
}
|
||||
|
||||
$oReflectionClass = new ReflectionClass(get_class($oVar));
|
||||
try{
|
||||
$oProperty = $oReflectionClass->getProperty($sName);
|
||||
if ($oProperty->isPublic()){
|
||||
return $oProperty->getValue($oVar);
|
||||
}
|
||||
} catch (\ReflectionException $t) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/SmallerEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/SmallerEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\Smaller;
|
||||
|
||||
class SmallerEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Smaller::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left < $right;
|
||||
}
|
||||
}
|
||||
16
sources/PhpParser/Evaluation/SmallerOrEqualEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/SmallerOrEqualEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\SmallerOrEqual;
|
||||
|
||||
class SmallerOrEqualEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return SmallerOrEqual::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left <= $right;
|
||||
}
|
||||
}
|
||||
49
sources/PhpParser/Evaluation/StaticCallEvaluator.php
Normal file
49
sources/PhpParser/Evaluation/StaticCallEvaluator.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use ModuleFileReaderException;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Identifier;
|
||||
|
||||
class StaticCallEvaluator extends AbstractExprEvaluator {
|
||||
public const WHITELIST=[
|
||||
"SetupInfo::ModuleIsSelected",
|
||||
"utils::GetItopVersionWikiSyntax"
|
||||
];
|
||||
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return StaticCall::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var StaticCall $oExpr */
|
||||
|
||||
$sClassName = $oExpr->class->name;
|
||||
if ($oExpr->name instanceof Identifier){
|
||||
$sMethodName = $oExpr->name->name;
|
||||
} else {
|
||||
$sMethodName = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name);
|
||||
}
|
||||
|
||||
$sStaticCallDescription = "$sClassName::$sMethodName";
|
||||
if (! in_array($sStaticCallDescription, self::WHITELIST)){
|
||||
throw new ModuleFileReaderException("StaticCall $sStaticCallDescription not supported");
|
||||
}
|
||||
|
||||
$aArgs=[];
|
||||
foreach ($oExpr->args as $arg){
|
||||
/** @var \PhpParser\Node\Arg $arg */
|
||||
$aArgs[]=$arg->value->value;
|
||||
}
|
||||
|
||||
$class = new \ReflectionClass($sClassName);
|
||||
$method = $class->getMethod($sMethodName);
|
||||
if (! $method->isPublic()){
|
||||
throw new ModuleFileReaderException("StaticCall $sStaticCallDescription not public");
|
||||
}
|
||||
|
||||
return $method->invokeArgs(null, $aArgs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
use PhpParser\Node\Identifier;
|
||||
|
||||
class StaticPropertyFetchEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return StaticPropertyFetch::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var StaticPropertyFetch $oExpr */
|
||||
|
||||
$sClassName = $oExpr->class->name;
|
||||
if ($oExpr->name instanceof Identifier){
|
||||
$sProperty = $oExpr->name->name;
|
||||
} else {
|
||||
$sProperty = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name);
|
||||
}
|
||||
|
||||
if (class_exists($sClassName)){
|
||||
$class = new \ReflectionClass($sClassName);
|
||||
if (array_key_exists($sProperty, $class->getStaticProperties())) {
|
||||
$oReflectionProperty = $class->getProperty($sProperty);
|
||||
if ($oReflectionProperty->isPublic()){
|
||||
return $class->getStaticPropertyValue($sProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
24
sources/PhpParser/Evaluation/TernaryEvaluator.php
Normal file
24
sources/PhpParser/Evaluation/TernaryEvaluator.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
|
||||
class TernaryEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Ternary::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var Ternary $oExpr */
|
||||
|
||||
$cond = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->cond);
|
||||
|
||||
if ($cond){
|
||||
return PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->if);
|
||||
}
|
||||
|
||||
return PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->else);
|
||||
}
|
||||
}
|
||||
18
sources/PhpParser/Evaluation/UnaryMinusEvaluator.php
Normal file
18
sources/PhpParser/Evaluation/UnaryMinusEvaluator.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\UnaryMinus;
|
||||
|
||||
class UnaryMinusEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return UnaryMinus::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var UnaryMinus $oExpr */
|
||||
|
||||
return - PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->expr);
|
||||
}
|
||||
}
|
||||
18
sources/PhpParser/Evaluation/UnaryPlusEvaluator.php
Normal file
18
sources/PhpParser/Evaluation/UnaryPlusEvaluator.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\UnaryPlus;
|
||||
|
||||
class UnaryPlusEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return UnaryPlus::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var UnaryPlus $oExpr */
|
||||
|
||||
return + PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->expr);
|
||||
}
|
||||
}
|
||||
28
sources/PhpParser/Evaluation/VariableEvaluator.php
Normal file
28
sources/PhpParser/Evaluation/VariableEvaluator.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
|
||||
class VariableEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Variable::class;
|
||||
}
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var Variable $oExpr */
|
||||
$sName = $oExpr->name;
|
||||
|
||||
if (array_key_exists($sName, get_defined_vars())) {
|
||||
return $$sName;
|
||||
}
|
||||
|
||||
if (array_key_exists($sName, $GLOBALS)) {
|
||||
global $$sName;
|
||||
return $$sName;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
11
sources/PhpParser/Evaluation/iExprEvaluator.php
Normal file
11
sources/PhpParser/Evaluation/iExprEvaluator.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
interface iExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string;
|
||||
public function GetHandledExpressionTypes(): ?array ;
|
||||
public function Evaluate(Expr $oExpr) : mixed;
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Setup\ModuleDiscovery;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use ModuleFileReader;
|
||||
|
||||
class ModuleFileReaderTest extends ItopDataTestCase
|
||||
{
|
||||
private string $sTempModuleFilePath;
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->RequireOnceItopFile('setup/modulediscovery/ModuleFileReader.php');
|
||||
}
|
||||
|
||||
public function testReadModuleFileInformationUnsafe()
|
||||
{
|
||||
$sModuleFilePath = __DIR__.'/resources/all/module.itop-full-itil.php';
|
||||
$aRes = ModuleFileReader::GetInstance()->ReadModuleFileInformationUnsafe($sModuleFilePath);
|
||||
|
||||
$this->assertCount(3, $aRes);
|
||||
$this->assertEquals($sModuleFilePath, $aRes[0]);
|
||||
$this->assertEquals('itop-full-itil/3.3.0', $aRes[1]);
|
||||
$this->assertIsArray($aRes[2]);
|
||||
$this->assertArrayHasKey('label', $aRes[2]);
|
||||
$this->assertEquals('Bridge - Request management ITIL + Incident management ITIL', $aRes[2]['label'] ?? null);
|
||||
}
|
||||
|
||||
public static function ReadModuleFileConfigurationFileNameProvider()
|
||||
{
|
||||
$aUsecases=[];
|
||||
foreach (glob(__DIR__.'/resources/all/*.php') as $sModuleFilePath){
|
||||
$aUsecases[basename($sModuleFilePath)]=[$sModuleFilePath];
|
||||
}
|
||||
return $aUsecases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ReadModuleFileConfigurationFileNameProvider
|
||||
*/
|
||||
public function testReadModuleFileConfigurationVsLegacyMethod(string $sModuleFilePath)
|
||||
{
|
||||
$_SERVER=[
|
||||
'SERVER_NAME' => 'titi'
|
||||
];
|
||||
$aRes = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sModuleFilePath);
|
||||
$aExpected = ModuleFileReader::GetInstance()->ReadModuleFileInformationUnsafe($sModuleFilePath);
|
||||
|
||||
$this->assertEquals($aExpected, $aRes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Covers below legacy usecase
|
||||
* 'dependencies' => array(
|
||||
* 'itop-config-mgmt/2.0.0'||'itop-structure/3.0.0',
|
||||
* 'itop-request-mgmt/2.0.0||itop-request-mgmt-itil/2.0.0||itop-incident-mgmt-itil/2.0.0',
|
||||
* ),
|
||||
*
|
||||
* @param string $sModuleBasename
|
||||
*
|
||||
* @return void
|
||||
* @throws \ModuleFileReaderException
|
||||
*/
|
||||
public function testReadModuleFileConfiguration_BadlyWrittenDependencies(){
|
||||
$sModuleFilePath = __DIR__."/resources/all/module.itop-admin-delegation-profiles.php";
|
||||
$aRes = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sModuleFilePath);
|
||||
$aExpected = ModuleFileReader::GetInstance()->ReadModuleFileInformationUnsafe($sModuleFilePath);
|
||||
|
||||
$this->assertEquals($aExpected, $aRes);
|
||||
}
|
||||
|
||||
public function testReadModuleFileConfigurationParsingIssue()
|
||||
{
|
||||
$sModuleFilePath = __DIR__.'/resources/module.__MODULE__.php';
|
||||
|
||||
$this->expectException(\ModuleFileReaderException::class);
|
||||
$this->expectExceptionMessage("Syntax error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting ',' or ']' or ')' on line 31");
|
||||
|
||||
ModuleFileReader::GetInstance()->ReadModuleFileInformation($sModuleFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* local tool function
|
||||
*/
|
||||
private function CallReadModuleFileConfiguration($sPHpCode)
|
||||
{
|
||||
$this->sTempModuleFilePath = tempnam(__DIR__, "test");
|
||||
file_put_contents($this->sTempModuleFilePath, $sPHpCode);
|
||||
try {
|
||||
return ModuleFileReader::GetInstance()->ReadModuleFileInformation($this->sTempModuleFilePath);
|
||||
}
|
||||
finally {
|
||||
@unlink($this->sTempModuleFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
public function testReadModuleFileConfigurationCheckBasicStatementWithoutIf()
|
||||
{
|
||||
$sPHP = <<<PHP
|
||||
<?php
|
||||
\$a=1;
|
||||
SetupWebPage::AddModule("a", "noif", ["c" => "d"]);
|
||||
\$b=2;
|
||||
PHP;
|
||||
$val = $this->CallReadModuleFileConfiguration($sPHP);
|
||||
$this->assertEquals([$this->sTempModuleFilePath, "noif", ["c" => "d", 'module_file_path' => $this->sTempModuleFilePath]], $val);
|
||||
}
|
||||
|
||||
public function testReadModuleFileConfigurationCheckBasicStatement_IfConditionVerified()
|
||||
{
|
||||
$sPHP = <<<PHP
|
||||
<?php
|
||||
\$a=1;
|
||||
if (true){
|
||||
SetupWebPage::AddModule("a", "if", ["c" => "d"]);
|
||||
} elseif (true){
|
||||
SetupWebPage::AddModule("a", "elseif1", ["c" => "d"]);
|
||||
} elseif (true){
|
||||
SetupWebPage::AddModule("a", "elseif2", ["c" => "d"]);
|
||||
} else {
|
||||
SetupWebPage::AddModule("a", "else", ["c" => "d"]);
|
||||
}
|
||||
SetupWebPage::AddModule("a", "outsideif", ["c" => "d"]);
|
||||
\$b=2;
|
||||
PHP;
|
||||
$val = $this->CallReadModuleFileConfiguration($sPHP);
|
||||
$this->assertEquals([$this->sTempModuleFilePath, "if", ["c" => "d", 'module_file_path' => $this->sTempModuleFilePath]], $val);
|
||||
}
|
||||
|
||||
public function testReadModuleFileConfigurationCheckBasicStatement_IfNoConditionVerifiedAndNoElse()
|
||||
{
|
||||
$sPHP = <<<PHP
|
||||
<?php
|
||||
\$a=1;
|
||||
if (false){
|
||||
SetupWebPage::AddModule("a", "if", ["c" => "d"]);
|
||||
} elseif (false){
|
||||
SetupWebPage::AddModule("a", "elseif1", ["c" => "d"]);
|
||||
} elseif (false){
|
||||
SetupWebPage::AddModule("a", "elseif2", ["c" => "d"]);
|
||||
}
|
||||
SetupWebPage::AddModule("a", "outsideif", ["c" => "d"]);
|
||||
\$b=2;
|
||||
PHP;
|
||||
$val = $this->CallReadModuleFileConfiguration($sPHP);
|
||||
$this->assertEquals([$this->sTempModuleFilePath, "outsideif", ["c" => "d", 'module_file_path' => $this->sTempModuleFilePath]], $val);
|
||||
}
|
||||
|
||||
public function testReadModuleFileConfigurationCheckBasicStatement_ElseApplied()
|
||||
{
|
||||
$sPHP = <<<PHP
|
||||
<?php
|
||||
\$a=1;
|
||||
if (false){
|
||||
SetupWebPage::AddModule("a", "if", ["c" => "d"]);
|
||||
} elseif (false){
|
||||
SetupWebPage::AddModule("a", "elseif1", ["c" => "d"]);
|
||||
} elseif (false){
|
||||
SetupWebPage::AddModule("a", "elseif2", ["c" => "d"]);
|
||||
} else {
|
||||
SetupWebPage::AddModule("a", "else", ["c" => "d"]);
|
||||
}
|
||||
SetupWebPage::AddModule("a", "outsideif", ["c" => "d"]);
|
||||
\$b=2;
|
||||
PHP;
|
||||
$val = $this->CallReadModuleFileConfiguration($sPHP);
|
||||
$this->assertEquals([$this->sTempModuleFilePath, "else", ["c" => "d", 'module_file_path' => $this->sTempModuleFilePath]], $val);
|
||||
}
|
||||
|
||||
public function testReadModuleFileConfigurationCheckBasicStatement_FirstElseIfApplied()
|
||||
{
|
||||
$sPHP = <<<PHP
|
||||
<?php
|
||||
\$a=1;
|
||||
if (false){
|
||||
SetupWebPage::AddModule("a", "if", ["c" => "d"]);
|
||||
} elseif (true){
|
||||
SetupWebPage::AddModule("a", "elseif1", ["c" => "d"]);
|
||||
} elseif (true){
|
||||
SetupWebPage::AddModule("a", "elseif2", ["c" => "d"]);
|
||||
} else {
|
||||
SetupWebPage::AddModule("a", "else", ["c" => "d"]);
|
||||
}
|
||||
SetupWebPage::AddModule("a", "outsideif", ["c" => "d"]);
|
||||
\$b=2;
|
||||
PHP;
|
||||
$val = $this->CallReadModuleFileConfiguration($sPHP);
|
||||
$this->assertEquals([$this->sTempModuleFilePath, "elseif1", ["c" => "d", 'module_file_path' => $this->sTempModuleFilePath]], $val);
|
||||
}
|
||||
|
||||
public function testReadModuleFileConfigurationCheckBasicStatement_LastElseIfApplied()
|
||||
{
|
||||
$sPHP = <<<PHP
|
||||
<?php
|
||||
\$a=1;
|
||||
if (false){
|
||||
SetupWebPage::AddModule("a", "if", ["c" => "d"]);
|
||||
} elseif (false){
|
||||
SetupWebPage::AddModule("a", "elseif1", ["c" => "d"]);
|
||||
} elseif (true){
|
||||
SetupWebPage::AddModule("a", "elseif2", ["c" => "d"]);
|
||||
} else {
|
||||
SetupWebPage::AddModule("a", "else", ["c" => "d"]);
|
||||
}
|
||||
SetupWebPage::AddModule("a", "outsideif", ["c" => "d"]);
|
||||
\$b=2;
|
||||
PHP;
|
||||
$val = $this->CallReadModuleFileConfiguration($sPHP);
|
||||
$this->assertEquals([$this->sTempModuleFilePath, "elseif2", ["c" => "d", 'module_file_path' => $this->sTempModuleFilePath]], $val);
|
||||
}
|
||||
|
||||
public function testGetAndCheckModuleInstallerClass()
|
||||
{
|
||||
$sModuleInstallerClass = "TicketsInstaller" . uniqid();
|
||||
$sPHpCode = file_get_contents(__DIR__.'/resources/all/module.itop-tickets.php');
|
||||
$sPHpCode = str_replace("TicketsInstaller", $sModuleInstallerClass, $sPHpCode);
|
||||
$this->sTempModuleFilePath = tempnam(__DIR__, "test");
|
||||
file_put_contents($this->sTempModuleFilePath, $sPHpCode);
|
||||
var_dump($sPHpCode);
|
||||
|
||||
try {
|
||||
$this->assertFalse(class_exists($sModuleInstallerClass));
|
||||
$aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($this->sTempModuleFilePath);
|
||||
$this->assertFalse(class_exists($sModuleInstallerClass));
|
||||
|
||||
$this->assertEquals($sModuleInstallerClass, ModuleFileReader::GetInstance()->GetAndCheckModuleInstallerClass($aModuleInfo[2]));
|
||||
}
|
||||
finally {
|
||||
@unlink($this->sTempModuleFilePath);
|
||||
}
|
||||
|
||||
$this->assertTrue(class_exists($sModuleInstallerClass));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
|
||||
// Until we develop a mean to adress this within the setup, let's check that this instance
|
||||
// of PHP has the php_ldap extension
|
||||
//
|
||||
if (function_exists('ldap_connect'))
|
||||
{
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-ldap/3.3.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'User authentication based on LDAP',
|
||||
'category' => 'authentication',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
),
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => 'AuthentLDAPInstaller',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
),
|
||||
'data.struct' => array(
|
||||
//'data.struct.authent-ldap.xml',
|
||||
),
|
||||
'data.sample' => array(
|
||||
//'data.sample.authent-ldap.xml',
|
||||
),
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '',
|
||||
'doc.more_information' => '',
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(
|
||||
'uri' => 'ldap://localhost', // URI with host or IP address of your LDAP server
|
||||
'default_user' => '', // User and password used for initial "Anonymous" bind to LDAP
|
||||
'default_pwd' => '', // Leave both blank, if anonymous (read-only) bind is allowed
|
||||
'base_dn' => 'dc=yourcompany,dc=com', // Base DN for User queries, adjust it to your LDAP schema
|
||||
'user_query' => '(&(uid=%1$s)(inetuserstatus=ACTIVE))', // Query used to retrieve each user %1$s => iTop login
|
||||
// For Windows AD use (samaccountname=%1$s) or (userprincipalname=%1$s)
|
||||
|
||||
// Some extra LDAP options, refer to: http://www.php.net/manual/en/function.ldap-set-option.php for more info
|
||||
'options' => array(
|
||||
LDAP_OPT_PROTOCOL_VERSION => 3,
|
||||
LDAP_OPT_REFERRALS => 0,
|
||||
),
|
||||
'start_tls' => false,
|
||||
'debug' => false,
|
||||
'servers' => array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Module installation handler
|
||||
//
|
||||
class AuthentLDAPInstaller extends ModuleInstallerAPI
|
||||
{
|
||||
public static function AfterDataLoad(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static function BeforeWritingConfig(Config $oConfiguration)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} // if (function_exists('ldap_connect'))
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'combodo-email-synchro/3.8.2',
|
||||
array(
|
||||
// Identification
|
||||
'label' => 'Tickets synchronization via e-mail',
|
||||
'category' => 'business',
|
||||
// Setup
|
||||
'dependencies' => array(
|
||||
'itop-profiles-itil/3.0.0',
|
||||
),
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => 'EmailSynchroInstaller',
|
||||
// Components
|
||||
'datamodel' => array(
|
||||
'classes/autoload.php',
|
||||
'model.combodo-email-synchro.php',
|
||||
),
|
||||
'dictionary' => array(),
|
||||
'data.struct' => array(
|
||||
),
|
||||
'data.sample' => array(
|
||||
),
|
||||
// Documentation
|
||||
'doc.manual_setup' => '', // No manual installation required
|
||||
'doc.more_information' => '', // None
|
||||
// Default settings
|
||||
'settings' => array(
|
||||
'notify_errors_to' => '', // mandatory to track errors not handled by the email processing module
|
||||
'notify_errors_from' => '', // mandatory as well (can be set at the same value as notify_errors_to)
|
||||
'debug' => false, // Set to true to turn on debugging
|
||||
'periodicity' => 30, // interval at which to check for incoming emails (in s)
|
||||
'retention_period' => 1, // number of hour we keep the replica
|
||||
'body_parts_order' => 'text/html,text/plain', // Order in which to read the parts of the incoming emails
|
||||
'pop3_auth_option' => 'USER',
|
||||
'imap_options' => array('imap'),
|
||||
'imap_open_options' => array(),
|
||||
'maximum_email_size' => '10M', // Maximum allowed size for incoming emails
|
||||
'big_files_dir' => '',
|
||||
'exclude_attachment_types' => array('application/exe'), // Example: 'application/exe', 'application/x-winexe', 'application/msdos-windows'
|
||||
// Lines to be removed just above the 'new part' in a reply-to message... add your own patterns below
|
||||
'introductory-patterns' => array(
|
||||
'/^le .+ a écrit :$/i', // Thunderbird French
|
||||
'/^on .+ wrote:$/i', // Thunderbird English
|
||||
'|^[0-9]{4}/[0-9]{1,2}/[0-9]{1,2} .+:$|', // Gmail style
|
||||
),
|
||||
// Some patterns which delimit the previous message in case of a Reply
|
||||
// The "new" part of the message is the text before the pattern
|
||||
// Add your own multi-line patterns (use \\R for a line break)
|
||||
// These patterns depend on the mail client/server used... feel free to add your own discoveries to the list
|
||||
'multiline-delimiter-patterns' => array(
|
||||
'/\\RFrom: .+\\RSent: .+\\R/m', // Outlook English
|
||||
'/\\R_+\\R/m', // A whole line made only of underscore characters
|
||||
'/\\RDe : .+\\R\\R?Envoyé : /m', // Outlook French, HTML and rich text
|
||||
'/\\RDe : .+\\RDate d\'envoi : .+\\R/m', // Outlook French, plain text
|
||||
'/\\R-----Message d\'origine-----\\R/m',
|
||||
),
|
||||
'use_message_id_as_uid' => false, // Do NOT change this unless you known what you are doing!!
|
||||
'images_minimum_size' => '100x20', // Images smaller that these dimensions will be ignored (signatures...)
|
||||
'images_maximum_size' => '', // Images bigger that these dimensions will be resized before uploading into iTop
|
||||
'recommended_max_allowed_packet' => 10*1024*1024, // MySQL parameter for attachments
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if (!class_exists('EmailSynchroInstaller'))
|
||||
{
|
||||
|
||||
// Module installation handler
|
||||
//
|
||||
class EmailSynchroInstaller extends ModuleInstallerAPI
|
||||
{
|
||||
|
||||
/**
|
||||
* Handler called after the creation/update of the database schema
|
||||
*
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string Previous version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// For each email sources, update email replicas by setting mailbox_path to source.mailbox where mailbox_path is null
|
||||
SetupLog::Info("Updating email replicas to set their mailbox path.");
|
||||
|
||||
// Preparing mailboxes search
|
||||
$oSearch = new DBObjectSearch('MailInboxBase');
|
||||
|
||||
// Retrieving definition of attribute to update
|
||||
$sTableName = MetaModel::DBGetTable('EmailReplica');
|
||||
|
||||
$UidlAttDef = MetaModel::GetAttributeDef('EmailReplica', 'uidl');
|
||||
$sUidlColName = $UidlAttDef->Get('sql');
|
||||
|
||||
$oMailboxAttDef = MetaModel::GetAttributeDef('EmailReplica', 'mailbox_path');
|
||||
$sMailboxColName = $oMailboxAttDef->Get('sql');
|
||||
|
||||
$sFrienlynameAttCode = MetaModel::GetFriendlyNameAttributeCode('EmailReplica');
|
||||
|
||||
// Looping on inboxes to update
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
while ($oInbox = $oSet->Fetch())
|
||||
{
|
||||
$sUpdateQuery = "UPDATE $sTableName SET $sMailboxColName = " . CMDBSource::Quote($oInbox->Get('mailbox')) . " WHERE $sUidlColName LIKE " . CMDBSource::Quote($oInbox->Get('login') . '_%') . " AND $sMailboxColName IS NULL";
|
||||
SetupLog::Info("Executing query: " . $sUpdateQuery);
|
||||
$iRet = CMDBSource::Query($sUpdateQuery); // Throws an exception in case of error
|
||||
SetupLog::Info("Updated $iRet rows.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
//
|
||||
// iTop module definition file
|
||||
//
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-admin-delegation-profiles-bridge-for-combodo-email-synchro/1.0.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Profiles per admin fonction: Mail inboxes and messages',
|
||||
'category' => 'Datamodel',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
'itop-admin-delegation-profiles/1.0.0',
|
||||
'itop-admin-delegation-profiles/1.0.0 || combodo-email-synchro/3.7.2 || itop-oauth-client/2.7.7', // Optional dependency to silence the setup to not display a warning if the other module is not present
|
||||
),
|
||||
'mandatory' => false,
|
||||
'visible' => false,
|
||||
'auto_select' => 'SetupInfo::ModuleIsSelected("itop-admin-delegation-profiles") && SetupInfo::ModuleIsSelected("combodo-email-synchro") && SetupInfo::ModuleIsSelected("itop-oauth-client")',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
'model.itop-admin-delegation-profiles-bridge-for-combodo-email-synchro.php'
|
||||
),
|
||||
'webservice' => array(
|
||||
|
||||
),
|
||||
'data.struct' => array(
|
||||
// add your 'structure' definition XML files here,
|
||||
),
|
||||
'data.sample' => array(
|
||||
// add your sample data XML files here,
|
||||
),
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
|
||||
'doc.more_information' => '', // hyperlink to more information, if any
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(
|
||||
// Module specific settings go here, if any
|
||||
),
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
//
|
||||
// iTop module definition file
|
||||
//
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-admin-delegation-profiles/1.2.1',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Profiles per admin fonction',
|
||||
'category' => 'Datamodel',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
'itop-config-mgmt/2.7.0' || 'itop-structure/3.0.0',
|
||||
// itop-profiles-itil is here to ensure that the /itop_design/groups/group[@id="History"] alteration comes after those from that module.
|
||||
// This allows to define the missing "History" group in iTop 2.7 / 3.0, while merging smoothly with iTop 3.1+
|
||||
'itop-profiles-itil/2.7.0',
|
||||
),
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
'model.itop-admin-delegation-profiles.php'
|
||||
),
|
||||
'webservice' => array(
|
||||
|
||||
),
|
||||
'data.struct' => array(
|
||||
// add your 'structure' definition XML files here,
|
||||
),
|
||||
'data.sample' => array(
|
||||
// add your sample data XML files here,
|
||||
),
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
|
||||
'doc.more_information' => '', // hyperlink to more information, if any
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(
|
||||
// Module specific settings go here, if any
|
||||
),
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
//
|
||||
// iTop module definition file
|
||||
//
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-full-itil/3.3.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Bridge - Request management ITIL + Incident management ITIL',
|
||||
'category' => 'business',
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
'itop-request-mgmt-itil/2.3.0',
|
||||
'itop-incident-mgmt-itil/2.3.0',
|
||||
),
|
||||
'mandatory' => false,
|
||||
'visible' => false,
|
||||
'auto_select' => 'SetupInfo::ModuleIsSelected("itop-request-mgmt-itil") && SetupInfo::ModuleIsSelected("itop-incident-mgmt-itil")',
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(),
|
||||
'webservice' => array(),
|
||||
'data.struct' => array(// add your 'structure' definition XML files here,
|
||||
),
|
||||
'data.sample' => array(// add your sample data XML files here,
|
||||
),
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
|
||||
'doc.more_information' => '', // hyperlink to more information, if any
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(// Module specific settings go here, if any
|
||||
),
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Module itop-global-requests
|
||||
*
|
||||
* @copyright Copyright (C) 2012-2019 Combodo SARL
|
||||
* @license https://www.combodo.com/documentation/combodo-software-license.html
|
||||
*/
|
||||
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-global-requests-mgmt/1.6.3',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'iTop Global Requests Management',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
'itop-portal-base/3.2.0',
|
||||
),
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => GlobalRequestInstaller::class,
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
'vendor/autoload.php',
|
||||
),
|
||||
'webservice' => array(),
|
||||
'data.struct' => array(// add your 'structure' definition XML files here,
|
||||
),
|
||||
'data.sample' => array(// add your sample data XML files here,
|
||||
),
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
|
||||
'doc.more_information' => '', // hyperlink to more information, if any
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(
|
||||
'target_state' => 'new',
|
||||
'bypass_profiles' => 'Administrator, Service Manager',
|
||||
'reuse_previous_answers' => true,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
class GlobalRequestInstaller extends ModuleInstallerAPI
|
||||
{
|
||||
/**
|
||||
* Handler called before creating or upgrading the database schema
|
||||
*
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string Previous version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
//code
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__,
|
||||
'itop-tickets/3.3.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Tickets Management',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
'itop-structure/2.7.1',
|
||||
),
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => 'TicketsInstaller',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
'main.itop-tickets.php',
|
||||
),
|
||||
'data.struct' => array(
|
||||
// 'data.struct.ta-actions.xml',
|
||||
),
|
||||
'data.sample' => array(
|
||||
),
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '',
|
||||
'doc.more_information' => '',
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Module installation handler
|
||||
//
|
||||
class TicketsInstaller extends ModuleInstallerAPI
|
||||
{
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// Delete all Triggers corresponding to a no more valid class
|
||||
CMDBObject::SetTrackInfo('Uninstallation');
|
||||
$oSearch = new DBObjectSearch('TriggerOnObject');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
while($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!MetaModel::IsValidClass($oTrigger->Get('target_class')))
|
||||
{
|
||||
$oTrigger->DBDelete();
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
// It's not very clear if it make sense to test a particular version,
|
||||
// as the loading mechanism checks object existence using reconc_keys
|
||||
// and do not recreate them, nor update existing.
|
||||
// Without test, new entries added to the data files, would be automatically loaded
|
||||
if (($sPreviousVersion === '') ||
|
||||
(version_compare($sPreviousVersion, $sCurrentVersion, '<')
|
||||
&& version_compare($sPreviousVersion, '3.0.0', '<'))) {
|
||||
$oDataLoader = new XMLDataLoader();
|
||||
|
||||
CMDBObject::SetTrackInfo("Initialization TicketsInstaller");
|
||||
$oMyChange = CMDBObject::GetCurrentChange();
|
||||
|
||||
$sLang = null;
|
||||
// - Try to get app. language from configuration fil (app. upgrade)
|
||||
$sConfigFileName = APPCONF.'production/'.ITOP_CONFIG_FILE;
|
||||
if (file_exists($sConfigFileName)) {
|
||||
$oFileConfig = new Config($sConfigFileName);
|
||||
if (is_object($oFileConfig)) {
|
||||
$sLang = str_replace(' ', '_', strtolower($oFileConfig->GetDefaultLanguage()));
|
||||
}
|
||||
}
|
||||
|
||||
// - I still no language, get the default one
|
||||
if (null === $sLang) {
|
||||
$sLang = str_replace(' ', '_', strtolower($oConfiguration->GetDefaultLanguage()));
|
||||
}
|
||||
|
||||
$sFileName = dirname(__FILE__)."/data/{$sLang}.data.itop-tickets.xml";
|
||||
SetupLog::Info("Searching file: $sFileName");
|
||||
if (!file_exists($sFileName)) {
|
||||
$sFileName = dirname(__FILE__)."/data/en_us.data.itop-tickets.xml";
|
||||
}
|
||||
SetupLog::Info("Loading file: $sFileName");
|
||||
$oDataLoader->StartSession($oMyChange);
|
||||
$oDataLoader->LoadFile($sFileName, false, true);
|
||||
$oDataLoader->EndSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-__YEAR__ Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
//
|
||||
// iTop module definition file
|
||||
//
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'__module_full_name__',
|
||||
[
|
||||
// Identification
|
||||
//
|
||||
'label' => '__module_label__',
|
||||
'category' => '__module_category__',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [
|
||||
__module_dependencies__
|
||||
],
|
||||
'mandatory' => __module_mandatory__,
|
||||
'visible' => __module_visible__,
|
||||
__module_setup_handler_class__
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => [
|
||||
'vendor/autoload.php',
|
||||
__module_data_model__, // Contains the PHP code generated by the "compilation" of datamodel.__module_name__.xml
|
||||
],
|
||||
'webservice' => [],
|
||||
'data.struct' => [
|
||||
// add your 'structure' definition XML files here,
|
||||
],
|
||||
'data.sample' => [
|
||||
// add your sample data XML files here,
|
||||
],
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
|
||||
'doc.more_information' => '', // hyperlink to more information, if any
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => [
|
||||
// Module specific settings go here, if any
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
__module_setup_handler__
|
||||
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Sources\PhpParser\Evaluation;
|
||||
|
||||
use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
class PhpExpressionEvaluatorTest extends ItopDataTestCase {
|
||||
public static $STATIC_PROPERTY = 123;
|
||||
private static $PRIVATE_STATIC_PROPERTY = 123;
|
||||
private const PRIVATE_CONSTANT = 123;
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown(); // TODO: Change the autogenerated stub
|
||||
PhpExpressionEvaluator::GetInstance()->SetMode(PhpExpressionEvaluator::ITOP_ALGO);
|
||||
}
|
||||
|
||||
public static function EvaluateExpressionProvider() {
|
||||
return [
|
||||
'Array: [1000 => "a"]' => ['sExpression' => '[1000 => "a"]'],
|
||||
'Array: ["a"]' => ['sExpression' => '["a"]'],
|
||||
'Array dict: ["a"=>"b"]' => ['sExpression' => '["a"=>"b"]'],
|
||||
'ArrayDimFetch: $_SERVER[\'toto\']' => ['sExpression' => '$_SERVER[\'toto\']'],
|
||||
'BinaryOperator: false|true' => [ 'sExpression' => 'false|true'],
|
||||
'BinaryOperator: false||true' => [ 'sExpression' => 'false||true'],
|
||||
'BinaryOperator: false&&true' => [ 'sExpression' => 'false&&true'],
|
||||
'BinaryOperator: true&&true&&true&&false' => [ 'sExpression' => 'true && true && true && false'],
|
||||
'BinaryOperator: false&true' => [ 'sExpression' => 'false&true'],
|
||||
'BinaryOperator: ! true' => [ 'sExpression' => '! true'],
|
||||
'BinaryOperator: 10 * 5' => [ 'sExpression' => '10 * 5'],
|
||||
'BinaryOperator: 1 > 2' => [ 'sExpression' => '1 > 2'],
|
||||
'BinaryOperator: 1 >= 1' => [ 'sExpression' => '1 >= 1'],
|
||||
'BinaryOperator: 1 <= 1' => [ 'sExpression' => '1 <= 1'],
|
||||
'BinaryOperator: PHP_VERSION_ID == PHP_VERSION_ID' => [ 'sExpression' => 'PHP_VERSION_ID == PHP_VERSION_ID'],
|
||||
'BinaryOperator: PHP_VERSION_ID != PHP_VERSION_ID' => [ 'sExpression' => 'PHP_VERSION_ID != PHP_VERSION_ID'],
|
||||
'BitwiseNot: ~3' => ['sExpression' => '~3'],
|
||||
'BitwiseXor: 3^2' => ['sExpression' => '3^2'],
|
||||
'BooleanAnd: true && false' => ['sExpression' => 'true && false'],
|
||||
'Cast: (array)3' => ['sExpression' => '(array)3'],
|
||||
'Cast: (bool)1' => ['sExpression' => '(bool)1'],
|
||||
'Cast: (bool)0' => ['sExpression' => '(bool)0'],
|
||||
'Cast: (double)3' => ['sExpression' => '(double)3'],
|
||||
'Cast: (float)3' => ['sExpression' => '(float)3'],
|
||||
'Cast: (int)3' => ['sExpression' => '(int)3'],
|
||||
'Cast: (object)3' => ['sExpression' => '(object)3'],
|
||||
'Cast: (string) $oEvaluationFakeClass' => ['sExpression' => '(string) $oEvaluationFakeClass', "toString"],
|
||||
'ClassConstFetch: public existing constant' => [ 'sExpression' => 'SetupUtils::PHP_MIN_VERSION'],
|
||||
'ClassConstFetch: unknown constant' => [ 'sExpression' => 'SetupUtils::UNKNOWN_CONSTANT'],
|
||||
'ClassConstFetch: unknown class:constant' => [ 'sExpression' => 'GabuZomeuUnknownClass::UNKNOWN_CONSTANT'],
|
||||
'ClassConstFetch: unknown class:class' => [ 'sExpression' => 'GabuZomeuUnknownClass::class'],
|
||||
'ClassConstFetch: private existing constant' => [
|
||||
'sExpression' => 'Combodo\iTop\Test\UnitTest\Setup\ModuleDiscovery\PhpExpressionEvaluatorTest::PRIVATE_CONSTANT',
|
||||
'forced_expected' => null,
|
||||
],
|
||||
'Coalesce: $oNullVar ?? 1' => ['sExpression' => '$oNullVar ?? 1', 1],
|
||||
'Coalesce: $oNonNullVar ?? 1' => ['sExpression' => '$oNonNullVar ?? 1', 1],
|
||||
'Coalesce: $_SERVER["toto"] ?? 1' => ['sExpression' => '$_SERVER["toto"] ?? 1', "titi"],
|
||||
'Coalesce: $_SERVER["unknown_key"] ?? 1' => ['sExpression' => '$_SERVER["unknown_key"] ?? 1', 1],
|
||||
'Coalesce: $oGlobalNonNullVar ?? 1' => ['sExpression' => '$oGlobalNonNullVar ?? 1', "a"],
|
||||
'Coalesce: $oGlobalNullVar ?? 1' => ['sExpression' => '$oGlobalNullVar ?? 1', 1],
|
||||
'Concat: "a"."b"' => ['sExpression' => '"a"."b"'],
|
||||
'ConstFetch: false' => [ 'sExpression' => 'false'],
|
||||
'ConstFetch: (false)' => [ 'sExpression' => 'false'],
|
||||
'ConstFetch: true' => [ 'sExpression' => 'true'],
|
||||
'ConstFetch: (true)' => [ 'sExpression' => 'true'],
|
||||
'Equal: 1 == true' => [ 'sExpression' => '1 == true', true],
|
||||
'Equal: 1 == false' => [ 'sExpression' => '1 == false', false],
|
||||
'FuncCall: function_exists(\'ldap_connect\')' => [ 'sExpression' => 'function_exists(\'ldap_connect\')'],
|
||||
'FuncCall: function_exists(\'gabuzomeushouldnotexist\')' => [ 'sExpression' => 'function_exists(\'gabuzomeushouldnotexist\')'],
|
||||
'Identical: 1==="1"' => ['sExpression' => '1==="1"', false],
|
||||
'Identical: "1"==="1"' => ['sExpression' => '"1"==="1"', true],
|
||||
'Isset: isset($oNonNullVar)' => ['sExpression' => 'isset($oNonNullVar)', false],
|
||||
'Isset: isset($oGlobalNonNullVar)' => ['sExpression' => 'isset($oGlobalNonNullVar)', true],
|
||||
'Isset: isset($a, $_SERVER)' => ['sExpression' => 'isset($a, $_SERVER)', false],
|
||||
'Isset: isset($_SERVER)' => ['sExpression' => 'isset($_SERVER)', true],
|
||||
'Isset: isset($_SERVER, $a)' => ['sExpression' => 'isset($_SERVER, $a)', false],
|
||||
'Isset: isset($oGlobalNonNullVar, $_SERVER)' => ['sExpression' => 'isset($oGlobalNonNullVar, $_SERVER)', true],
|
||||
'MethodCall: $oEvaluationFakeClass->GetName()' => ['sExpression' => '$oEvaluationFakeClass->GetName()', "gabuzomeu"],
|
||||
'MethodCall: $oEvaluationFakeClass->GetLongName("aa")' => ['sExpression' => '$oEvaluationFakeClass->GetLongName("aa")', "gabuzomeu_aa"],
|
||||
'Mod: 3%2' => ['sExpression' => '3%2'],
|
||||
'NullsafeMethodCall: $oNullVar?->GetName()' => ['sExpression' => '$oNullVar?->GetName()', null],
|
||||
'NullsafeMethodCall: $oNullVar?->GetLongName("aa")' => ['sExpression' => '$oNullVar?->GetLongName("aa")', null],
|
||||
'NullsafeMethodCall: $oEvaluationFakeClass?->GetName()' => ['sExpression' => '$oEvaluationFakeClass?->GetName()', "gabuzomeu"],
|
||||
'NullsafeMethodCall: $oEvaluationFakeClass?->GetLongName("aa")' => ['sExpression' => '$oEvaluationFakeClass?->GetLongName("aa")', "gabuzomeu_aa"],
|
||||
'NullsafePropertyFetch: $oNullVar?->b' => ['sExpression' => '$oNullVar?->b', null],
|
||||
'NullsafePropertyFetch: $oEvaluationFakeClass?->iIsOk' => ['sExpression' => '$oEvaluationFakeClass?->iIsOk', "IsOkValue"],
|
||||
'PropertyFetch: $oEvaluationFakeClass->iIsOk' => ['sExpression' => '$oEvaluationFakeClass->iIsOk', "IsOkValue"],
|
||||
'StaticCall utils::GetItopVersionWikiSyntax()' => ['sExpression' => 'utils::GetItopVersionWikiSyntax()'],
|
||||
'StaticProperty: public existing constant' => [ 'sExpression' => 'Combodo\iTop\Test\UnitTest\Sources\PhpParser\Evaluation\PhpExpressionEvaluatorTest::$STATIC_PROPERTY'],
|
||||
'StaticProperty: private existing constant' => [
|
||||
'sExpression' => 'Combodo\iTop\Test\UnitTest\Setup\ModuleDiscovery\PhpExpressionEvaluatorTest::$PRIVATE_STATIC_PROPERTY',
|
||||
'forced_expected' => null,
|
||||
],
|
||||
'Ternary: (true) ? 1 : 2' => ['sExpression' => '(true) ? 1 : 2'],
|
||||
'Ternary: (false) ? 1 : 2' => ['sExpression' => '(false) ? 1 : 2'],
|
||||
'UnaryMinus: -1' => ['sExpression' => '-1'],
|
||||
'UnaryPlus: +1' => ['sExpression' => '+1'],
|
||||
'Variable: $_SERVER' => ['sExpression' => '$_SERVER', ['toto' => 'titi']],
|
||||
'Variable: $oNonNullVar' => ['sExpression' => '$oNonNullVar', null],
|
||||
'Variable: $oGlobalNonNullVar' => ['sExpression' => '$oGlobalNonNullVar', "a"],
|
||||
'Variable: $oEvaluationFakeClass' => ['sExpression' => '$oEvaluationFakeClass', new EvaluationFakeClass()],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider EvaluateExpressionProvider
|
||||
*/
|
||||
public function testEvaluateExpressionWithItopAlgo($sExpression, $forced_expected="NOTPROVIDED")
|
||||
{
|
||||
$this->evaluateExpressionWithMode($sExpression, $forced_expected, PhpExpressionEvaluator::ITOP_ALGO);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider EvaluateExpressionProvider
|
||||
*/
|
||||
public function testEvaluateExpressionWithLibAndItopFallback($sExpression, $forced_expected="NOTPROVIDED")
|
||||
{
|
||||
$this->evaluateExpressionWithMode($sExpression, $forced_expected, PhpExpressionEvaluator::LIB_AND_FALLBACK);
|
||||
}
|
||||
|
||||
public function evaluateExpressionWithMode($sExpression, $forced_expected, $iMode)
|
||||
{
|
||||
global $oGlobalNonNullVar;
|
||||
$oGlobalNonNullVar="a";
|
||||
|
||||
global $oGlobalNullVar;
|
||||
$oGlobalNullVar=null;
|
||||
|
||||
$oNonNullVar="a";
|
||||
|
||||
$oNullVar=null;
|
||||
$_SERVER=[
|
||||
'toto' => 'titi',
|
||||
];
|
||||
|
||||
global $oEvaluationFakeClass;
|
||||
$oEvaluationFakeClass = new EvaluationFakeClass();
|
||||
|
||||
PhpExpressionEvaluator::GetInstance()->SetMode($iMode);
|
||||
$res = PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateExpression($sExpression);
|
||||
if ($forced_expected === "NOTPROVIDED"){
|
||||
$this->assertEquals($this->UnprotectedComputeExpression($sExpression), $res, $sExpression);
|
||||
} else {
|
||||
$this->assertEquals($forced_expected, $res, $sExpression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sBooleanExpr
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \ModuleFileReaderException
|
||||
*/
|
||||
private function UnprotectedComputeExpression(string $sExpr) : mixed
|
||||
{
|
||||
try {
|
||||
$bResult = null;
|
||||
@eval('$bResult = '.$sExpr.';');
|
||||
|
||||
return $bResult;
|
||||
} catch (\Throwable $t){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static function ParseAndEvaluateBooleanExpression_AutoselectProvider()
|
||||
{
|
||||
$sSimpleCallToModuleIsSelected = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\")";
|
||||
$sSimpleCallToModuleIsSelected2 = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt-notselected\")";
|
||||
$sCallToModuleIsSelectedCombinedWithAndOperator = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\")";
|
||||
$sCallToModuleIsSelectedCombinedWithAndOperator2 = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt-notselected\") || SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\")";
|
||||
|
||||
return [
|
||||
"simple call to SetupInfo::ModuleIsSelected SELECTED" => [
|
||||
"expr" => $sSimpleCallToModuleIsSelected,
|
||||
"expected" => true,
|
||||
],
|
||||
"simple call to SetupInfo::ModuleIsSelected NOT SELECTED" => [
|
||||
"expr" => $sSimpleCallToModuleIsSelected2,
|
||||
"expected" => false,
|
||||
],
|
||||
"call to SetupInfo::ModuleIsSelected + OR => SELECTED" => [
|
||||
"expr" => $sCallToModuleIsSelectedCombinedWithAndOperator,
|
||||
"expected" => true,
|
||||
],
|
||||
"simple call to SetupInfo::ModuleIsSelected + OR => NOT SELECTED" => [
|
||||
"expr" => $sCallToModuleIsSelectedCombinedWithAndOperator2,
|
||||
"expected" => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider ParseAndEvaluateBooleanExpression_AutoselectProvider
|
||||
*/
|
||||
public function testEvaluateBooleanExpression_Autoselect(string $sBooleanExpression, bool $expected){
|
||||
\SetupInfo::SetSelectedModules(["itop-storage-mgmt" => "123"]);
|
||||
$this->assertEquals($expected, PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($sBooleanExpression), $sBooleanExpression);
|
||||
}
|
||||
}
|
||||
|
||||
class EvaluationFakeClass {
|
||||
public string $iIsOk="IsOkValue";
|
||||
|
||||
public function GetName()
|
||||
{
|
||||
return "gabuzomeu";
|
||||
}
|
||||
|
||||
public function GetLongName($suffix)
|
||||
{
|
||||
return "gabuzomeu_" . $suffix;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return "toString";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user