mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-24 02:58:43 +02:00
Merge branch 'develop' into feature/fast-theme-compilation2
This commit is contained in:
@@ -320,14 +320,27 @@ class MFCompiler
|
||||
}
|
||||
else
|
||||
{
|
||||
/** @var \DOMElement $oClass */
|
||||
/** @var \MFElement $oClass */
|
||||
foreach($oClasses as $oClass)
|
||||
{
|
||||
$sClass = $oClass->getAttribute("id");
|
||||
$aAllClasses[] = $sClass;
|
||||
try
|
||||
{
|
||||
$sCompiledCode .= $this->CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir);
|
||||
$aCompiledClasses = $this->CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir);
|
||||
|
||||
foreach ($aCompiledClasses['required_files'] as $sIncludeFile)
|
||||
{
|
||||
$sCompiledCode .= "require_once('$sIncludeFile');\n";
|
||||
}
|
||||
|
||||
foreach ($aCompiledClasses['code'] as $sClass => $sCompiledClass)
|
||||
{
|
||||
$sClassFileName = DIRECTORY_SEPARATOR.$sRelativeDir.DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'Model'.DIRECTORY_SEPARATOR.$sClass.'.php';
|
||||
$sClassFile = "{$sTempTargetDir}{$sClassFileName}";
|
||||
$this->WritePHPFile($sClassFile, $sModuleName, $sModuleVersion, $sCompiledClass);
|
||||
$sCompiledCode .= "require_once ('{$sFinalTargetDir}{$sClassFileName}');\n";
|
||||
}
|
||||
}
|
||||
catch (DOMFormatException $e)
|
||||
{
|
||||
@@ -468,49 +481,7 @@ EOF;
|
||||
// Write the code into the given module as model.<module>.php
|
||||
//
|
||||
$sResultFile = $sTempTargetDir.'/'.$sRelativeDir.'/model.'.$sModuleName.'.php';
|
||||
if (is_file($sResultFile))
|
||||
{
|
||||
$this->Log("Updating $sResultFile for module $sModuleName in version $sModuleVersion ($iClassCount classes)");
|
||||
} else
|
||||
{
|
||||
$sResultDir = dirname($sResultFile);
|
||||
if (!is_dir($sResultDir))
|
||||
{
|
||||
$this->Log("Creating directory $sResultDir");
|
||||
mkdir($sResultDir, 0777, true);
|
||||
}
|
||||
$this->Log("Creating $sResultFile for module $sModuleName in version $sModuleVersion ($iClassCount classes)");
|
||||
}
|
||||
|
||||
// Compile the module into a single file
|
||||
//
|
||||
$sCurrDate = date(DATE_ISO8601);
|
||||
$sAuthor = 'iTop compiler';
|
||||
$sLicence = 'http://opensource.org/licenses/AGPL-3.0';
|
||||
$sFileHeader =
|
||||
<<<EOF
|
||||
<?php
|
||||
//
|
||||
// File generated by ... on the $sCurrDate
|
||||
// Please do not edit manually
|
||||
//
|
||||
|
||||
/**
|
||||
* Classes and menus for $sModuleName (version $sModuleVersion)
|
||||
*
|
||||
* @author $sAuthor
|
||||
* @license $sLicence
|
||||
*/
|
||||
|
||||
EOF;
|
||||
$ret = file_put_contents($sResultFile, $sFileHeader.$sCompiledCode);
|
||||
if ($ret === false)
|
||||
{
|
||||
$iLen = strlen($sFileHeader.$sCompiledCode);
|
||||
$fFree = @disk_free_space(dirname($sResultFile));
|
||||
$aErr = error_get_last();
|
||||
throw new Exception("Failed to write '$sResultFile'. Last error: '{$aErr['message']}', content to write: $iLen bytes, available free space on disk: $fFree.");
|
||||
}
|
||||
$this->WritePHPFile($sResultFile, $sModuleName, $sModuleVersion, $sCompiledCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -613,8 +584,8 @@ EOF;
|
||||
SetupUtils::builddir($sTempTargetDir.'/core');
|
||||
$sPHPFile = $sTempTargetDir.'/core/main.php';
|
||||
file_put_contents($sPHPFile, $this->sMainPHPCode);
|
||||
|
||||
|
||||
$sCurrDate = date(DATE_ISO8601);
|
||||
// Autoload
|
||||
$sPHPFile = $sTempTargetDir.'/autoload.php';
|
||||
$sPHPFileContent =
|
||||
@@ -1020,7 +991,7 @@ EOF
|
||||
* @param string $sFinalTargetDir
|
||||
* @param string $sModuleRelativeDir
|
||||
*
|
||||
* @return string
|
||||
* @return array
|
||||
* @throws \DOMFormatException
|
||||
*/
|
||||
protected function CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sModuleRelativeDir)
|
||||
@@ -1999,7 +1970,7 @@ EOF
|
||||
$sClassName = $oClass->getAttribute('id');
|
||||
$bIsAbstractClass = ($oProperties->GetChildText('abstract') == 'true');
|
||||
$oPhpParent = $oClass->GetUniqueElement('php_parent', false);
|
||||
$aRequiredFiles = array();
|
||||
$aRequiredFiles = [];
|
||||
if ($oPhpParent)
|
||||
{
|
||||
$sParentClass = $oPhpParent->GetChildText('name', '');
|
||||
@@ -2032,8 +2003,7 @@ $sZlists;
|
||||
EOF;
|
||||
// some other stuff (magical attributes like friendlyName) are done in MetaModel::InitClasses and though not present in the
|
||||
// generated PHP
|
||||
$sPHP = $this->GeneratePhpCodeForClass($sClassName, $sParentClass, $sClassParams, $sInitMethodCalls,
|
||||
$bIsAbstractClass, $sMethods, $aRequiredFiles, $sCodeComment);
|
||||
$aPHP[$sClassName] = $this->GeneratePhpCodeForClass($sClassName, $sParentClass, $sClassParams, $sInitMethodCalls, $bIsAbstractClass, $sMethods, $sCodeComment);
|
||||
|
||||
// N°931 generates TagFieldData classes for AttributeTag fields
|
||||
if (!empty($aTagFieldsInfo))
|
||||
@@ -2062,11 +2032,11 @@ EOF
|
||||
{
|
||||
$sTagClassName = static::GetTagDataClassName($sClassName, $sTagFieldName);
|
||||
$sTagClassParams = var_export($aTagClassParams, true);
|
||||
$sPHP .= $this->GeneratePhpCodeForClass($sTagClassName, $sTagClassParentClass, $sTagClassParams, $sTagInitMethodCalls);
|
||||
$aPHP[$sTagClassName] = $this->GeneratePhpCodeForClass($sTagClassName, $sTagClassParentClass, $sTagClassParams, $sTagInitMethodCalls);
|
||||
}
|
||||
}
|
||||
|
||||
return $sPHP;
|
||||
return ['code' => $aPHP, 'required_files' => $aRequiredFiles];
|
||||
}
|
||||
|
||||
private static function GetTagDataClassName($sClass, $sAttCode)
|
||||
@@ -3018,22 +2988,21 @@ EOF;
|
||||
* @param bool $bIsAbstractClass
|
||||
* @param string $sMethods
|
||||
*
|
||||
* @param array $aRequiredFiles
|
||||
* @param string $sCodeComment
|
||||
*
|
||||
* @return string php code for the class
|
||||
*/
|
||||
private function GeneratePhpCodeForClass(
|
||||
$sClassName, $sParentClassName, $sClassParams, $sInitMethodCalls = '', $bIsAbstractClass = false, $sMethods = '',
|
||||
$aRequiredFiles = array(), $sCodeComment = ''
|
||||
$sClassName,
|
||||
$sParentClassName,
|
||||
$sClassParams,
|
||||
$sInitMethodCalls = '',
|
||||
$bIsAbstractClass = false,
|
||||
$sMethods = '',
|
||||
$sCodeComment = ''
|
||||
) {
|
||||
$sPHP = "\n\n$sCodeComment\n";
|
||||
|
||||
foreach ($aRequiredFiles as $sIncludeFile)
|
||||
{
|
||||
$sPHP .= "\nrequire_once('$sIncludeFile');\n";
|
||||
}
|
||||
|
||||
if ($bIsAbstractClass)
|
||||
{
|
||||
$sPHP .= 'abstract class '.$sClassName;
|
||||
@@ -3173,4 +3142,53 @@ XML;
|
||||
|
||||
$this->WriteFile("$sTempTargetDir/web.config", $sContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sResultFile
|
||||
* @param $sModuleName
|
||||
* @param $sModuleVersion
|
||||
* @param $sCompiledCode
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function WritePHPFile($sResultFile, $sModuleName, $sModuleVersion, $sCompiledCode)
|
||||
{
|
||||
if (is_file($sResultFile))
|
||||
{
|
||||
$this->Log("Updating $sResultFile for module $sModuleName in version $sModuleVersion");
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResultDir = dirname($sResultFile);
|
||||
if (!is_dir($sResultDir))
|
||||
{
|
||||
$this->Log("Creating directory $sResultDir");
|
||||
mkdir($sResultDir, 0777, true);
|
||||
}
|
||||
$this->Log("Creating $sResultFile for module $sModuleName in version $sModuleVersion");
|
||||
}
|
||||
|
||||
// Compile the module into a single file
|
||||
//
|
||||
$sCurrDate = date(DATE_ISO8601);
|
||||
$sAuthor = 'iTop compiler';
|
||||
$sLicence = 'http://opensource.org/licenses/AGPL-3.0';
|
||||
$sFileHeader =
|
||||
<<<EOF
|
||||
<?php
|
||||
//
|
||||
// File generated by ... on the $sCurrDate
|
||||
// Please do not edit manually
|
||||
//
|
||||
|
||||
/**
|
||||
* Classes and menus for $sModuleName (version $sModuleVersion)
|
||||
*
|
||||
* @author $sAuthor
|
||||
* @license $sLicence
|
||||
*/
|
||||
|
||||
EOF;
|
||||
$this->WriteFile($sResultFile, $sFileHeader.$sCompiledCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +277,6 @@ class iTopExtensionsMap
|
||||
$oExtension->sVersion = $oXml->Get('version');
|
||||
$oExtension->bMandatory = ($oXml->Get('mandatory') == 'true');
|
||||
$oExtension->sMoreInfoUrl = $oXml->Get('more_info_url');
|
||||
$oExtension->sVersion = $oXml->Get('version');
|
||||
$oExtension->sSource = $sSource;
|
||||
$oExtension->sSourceDir = $sSearchDir;
|
||||
|
||||
|
||||
@@ -256,18 +256,21 @@ class MFModule
|
||||
public function GetDictionaryFiles()
|
||||
{
|
||||
$aDictionaries = array();
|
||||
if ($hDir = opendir($this->sRootDir))
|
||||
foreach (array($this->sRootDir, $this->sRootDir.'/dictionaries') as $sRootDir)
|
||||
{
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
if ($hDir = @opendir($sRootDir))
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match("/^[^\\.]+.dict.".$this->sName.'.php$/i', $sFile,
|
||||
$aMatches)) // Dictionary files are named like <Lang>.dict.<ModuleName>.php
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
{
|
||||
$aDictionaries[] = $this->sRootDir.'/'.$sFile;
|
||||
$aMatches = array();
|
||||
if (preg_match("/^[^\\.]+.dict.".$this->sName.'.php$/i', $sFile,
|
||||
$aMatches)) // Dictionary files are named like <Lang>.dict.<ModuleName>.php
|
||||
{
|
||||
$aDictionaries[] = $sRootDir.'/'.$sFile;
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
|
||||
return $aDictionaries;
|
||||
@@ -466,18 +469,21 @@ class MFDictModule extends MFModule
|
||||
public function GetDictionaryFiles()
|
||||
{
|
||||
$aDictionaries = array();
|
||||
if ($hDir = opendir($this->sRootDir))
|
||||
foreach (array($this->sRootDir, $this->sRootDir.'/dictionaries') as $sRootDir)
|
||||
{
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
if ($hDir = @opendir($sRootDir))
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match("/^.*dictionary\\.itop.*.php$/i", $sFile,
|
||||
$aMatches)) // Dictionary files are named like <Lang>.dict.<ModuleName>.php
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
{
|
||||
$aDictionaries[] = $this->sRootDir.'/'.$sFile;
|
||||
$aMatches = array();
|
||||
if (preg_match("/^.*dictionary\\.itop.*.php$/i", $sFile,
|
||||
$aMatches)) // Dictionary files are named like <Lang>.dict.<ModuleName>.php
|
||||
{
|
||||
$aDictionaries[] = $sRootDir.'/'.$sFile;
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
|
||||
return $aDictionaries;
|
||||
@@ -2898,4 +2904,4 @@ class MFParameters
|
||||
|
||||
return $merged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,17 +134,20 @@ class ModuleDiscovery
|
||||
{
|
||||
$sModuleName = $aMatches[1];
|
||||
$sDir = dirname($sFilePath);
|
||||
if ($hDir = opendir($sDir))
|
||||
foreach (array($sDir, $sDir.'/dictionaries') as $sRootDir)
|
||||
{
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
if ($hDir = @opendir($sRootDir))
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match("/^[^\\.]+.dict.$sModuleName.php$/i", $sFile, $aMatches)) // Dictionary files named like <Lang>.dict.<ModuleName>.php are loaded automatically
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
{
|
||||
self::$m_aModules[$sId]['dictionary'][] = self::$m_sModulePath.'/'.$sFile;
|
||||
$aMatches = array();
|
||||
if (preg_match("/^[^\\.]+.dict.$sModuleName.php$/i", $sFile, $aMatches)) // Dictionary files named like <Lang>.dict.<ModuleName>.php are loaded automatically
|
||||
{
|
||||
self::$m_aModules[$sId]['dictionary'][] = $sRootDir.'/'.$sFile;
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,50 @@ class CheckResult
|
||||
$this->sLabel = $sLabel;
|
||||
$this->sDescription = $sDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 2.8.0 N°2214
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$sPrintDesc = (empty($this->sDescription)) ? '' : " ({$this->sDescription})";
|
||||
return "{$this->sLabel}$sPrintDesc";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \CheckResult[] $aResults
|
||||
*
|
||||
* @return \CheckResult[] only elements that are error (iSeverity===ERROR)
|
||||
*
|
||||
* @since 2.8.0 N°2214
|
||||
*/
|
||||
public static function KeepOnlyErrors($aResults)
|
||||
{
|
||||
return array_filter($aResults,
|
||||
static function ($v)
|
||||
{
|
||||
if ($v->iSeverity === CheckResult::ERROR) {
|
||||
return $v;
|
||||
}
|
||||
},
|
||||
ARRAY_FILTER_USE_BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \CheckResult[] $aResults
|
||||
*
|
||||
* @return string[]
|
||||
* @uses \CheckResult::__toString
|
||||
*
|
||||
* @since 2.8.0 N°2214
|
||||
*/
|
||||
public static function FromObjectsToStrings($aResults)
|
||||
{
|
||||
return array_map(function ($value) {
|
||||
return $value->__toString();
|
||||
}, $aResults);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,15 +94,15 @@ class CheckResult
|
||||
class SetupUtils
|
||||
{
|
||||
// -- Minimum versions (requirements : forbids installation if not met)
|
||||
const PHP_MIN_VERSION = '5.6.0'; // 5.6 will be supported until the end of 2018 (see http://php.net/supported-versions.php)
|
||||
const PHP_MIN_VERSION = '7.1.3'; // 7 will be supported until the end of 2019 (see http://php.net/supported-versions.php)
|
||||
const MYSQL_MIN_VERSION = '5.6.0'; // 5.6 to have fulltext on InnoDB for Tags fields (N°931)
|
||||
const MYSQL_NOT_VALIDATED_VERSION = ''; // MySQL 8 is now OK (N°2010 in 2.7.0) but has no query cache so mind the perf on large volumes !
|
||||
|
||||
// -- versions that will be the minimum in next iTop major release (warning if not met)
|
||||
const PHP_NEXT_MIN_VERSION = '7.1.3'; // we are aiming on switching to Symfony 4 in iTop 2.8
|
||||
const PHP_NEXT_MIN_VERSION = ''; //
|
||||
const MYSQL_NEXT_MIN_VERSION = ''; // no new MySQL requirement for next iTop version
|
||||
// -- First recent version that is not yet validated by Combodo (warning)
|
||||
const PHP_NOT_VALIDATED_VERSION = '7.5.0';
|
||||
const PHP_NOT_VALIDATED_VERSION = '8.0.0';
|
||||
|
||||
const MIN_MEMORY_LIMIT = 33554432; // 32 * 1024 * 1024 - we can use expressions in const since PHP 5.6 but we are in the setup !
|
||||
const SUHOSIN_GET_MAX_VALUE_LENGTH = 2048;
|
||||
@@ -370,6 +414,37 @@ class SetupUtils
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \CLIPage $oCliPage
|
||||
* @param int $iExitCode
|
||||
*
|
||||
* @since 2.8.0 N°2214
|
||||
*/
|
||||
public static function CheckPhpAndExtensionsForCli($oCliPage, $iExitCode = -1)
|
||||
{
|
||||
$aPhpCheckResults = self::CheckPhpAndExtensions();
|
||||
$aPhpCheckErrors = CheckResult::KeepOnlyErrors($aPhpCheckResults);
|
||||
if (empty($aPhpCheckErrors))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$sMessageTitle = 'Error: PHP minimum requirements are not met !';
|
||||
$oCliPage->p($sMessageTitle);
|
||||
$aPhpCheckErrorsForPrint = CheckResult::FromObjectsToStrings($aPhpCheckErrors);
|
||||
foreach ($aPhpCheckErrorsForPrint as $sError)
|
||||
{
|
||||
$oCliPage->p(' * '.$sError);
|
||||
}
|
||||
$oCliPage->output();
|
||||
|
||||
// some CLI scripts are launched automatically
|
||||
// we need a log so that we don't miss errors after migration !
|
||||
IssueLog::Error($oCliPage->s_title.' '.$sMessageTitle, 'CLI', $aPhpCheckErrorsForPrint);
|
||||
|
||||
exit($iExitCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CheckResult[] $aResult checks log
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user