Compare commits

..

34 Commits

Author SHA1 Message Date
odain
7f7ce0837e Merge branch 'designer-3.2.1' into support/3.2.1 2025-11-18 15:35:40 +01:00
odain
7df09541ac N°8306 - ci fixes 2025-11-16 08:11:34 +01:00
odain
7fb0ae48f9 Fix deprecated warning
<b>Deprecated</b>:  Return type of Combodo\iTop\DesignDocument::loadXML(string $source, int $options = 0) should either be compatible with DOMDocument::loadXML(string $source, int $options = 0): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in <b>/var/www/html/iTop/core/designdocument.class.inc.php</b> on line <b>73</b><br />
2025-11-15 21:26:36 +01:00
odain
e89a8edae0 N°8306 - fix MFEException use 2025-11-15 21:19:01 +01:00
odain
f6366057c9 Merge branch 'designer-3.2.1' into support/3.2.1 2025-11-14 10:18:46 +01:00
odain
b5c79e1d75 N°8912 - Cannot work on a licence with legacy extensions including modules without explicit version 2025-11-13 11:13:33 +01:00
Eric Espie
5045ec4afa N°7722 - Fatal error on xml injection if xml entry "redefine" doesn't exist 2025-09-25 09:43:19 +02:00
Eric Espie
88e0f17164 N°8306 - Wrong line number error if XML is over 65535 lines 2025-08-26 11:56:44 +02:00
Eric Espie
de54676b9f N°7938 - Cant' create OnInsert/OnUpdate/Afterxxx methods from Designer with iTop 3.2 2025-07-21 16:53:13 +02:00
Eric Espie
e5129c9618 N°7938 - tooltip error style 2025-07-16 15:22:10 +02:00
Eric Espie
d0f816109b N°7938 - Cant' create OnInsert/OnUpdate/Afterxxx methods from Designer with iTop 3.2 2025-07-16 13:22:50 +02:00
Eric Espie
05642cdf84 N°8306 - Wrong line number error if XML is over 65535 lines 2025-07-10 16:53:36 +02:00
Eric Espie
031305cfbf Add stack trace to SQL errors
Reload object on modify error to display the real unmodified object
2025-07-07 13:44:45 +02:00
odain
471422b274 N°8306 : enhance MFEException constructor and remove boilerplate throw method 2025-06-20 08:08:42 +02:00
odain
5573a222c8 N°8286 - fix call to CompleteSessionData in case of no proper session content 2025-06-19 11:32:23 +02:00
odain
83eb2b81e3 N°8306 : fix ModelFactoryEx class not found 2025-06-18 16:25:53 +02:00
odain
86d2a3424d N°8306 - Wrong line number error if XML is over 65535 lines 2025-06-18 15:45:39 +02:00
Eric Espie
cd1c6f5ec5 N°8404 - Error when upgrading composant version on Designer (Migration status on licence) 2025-06-16 08:59:43 +02:00
Eric Espie
2ee30692ff Change deprecated calls 2025-05-22 15:02:29 +02:00
odain
9aa13f57d8 N°8413 - Make data synchro work on DBObject 2025-05-21 10:12:11 +02:00
odain
f9d9fcc440 N°7398-log level with invalid json 2025-05-07 11:03:13 +02:00
odain
a4a05a2579 N°7398 - be able to add custom data in session files generated by SessionHandler 2025-05-07 11:03:05 +02:00
Benjamin Dalsass
f44468b7a1 N°8245 - External key not saved in n-n link in edition (#703)
* N°8245 - External key not saved in n-n link in edition

* Remove the listener from the input element itself, put it on the body with a selector that matches our input

* Revert "N°8245 - External key not saved in n-n link in edition"

This reverts commit a756f9b159.

---------

Co-authored-by: Stephen Abello <stephen.abello@combodo.com>
2025-03-24 14:05:30 +01:00
jf-cbd
7af1cdebfa Workaround for N°4459 doesn't work on 3.2 2025-03-24 11:21:41 +01:00
jf-cbd
a9fb5cd182 N°7870 - Tests: access the symfony service container to instantiate services 2025-03-24 11:02:34 +01:00
jf-cbd
9010504902 Fix tests 2025-03-24 10:53:18 +01:00
jf-cbd
2625b1ab54 Update tests for 3.1 2025-03-24 10:52:47 +01:00
Molkobain
b967338c48 🐛 N°8278 - Avoid autoloaders class name conflict by ensuring all existing have a unique name (#704)
* 🐛 Avoid autoloaders class name conflict by ensuring all existing have a unique name

* 🐛 Redump itop-attachments autoloaders for correct suffix
2025-03-24 10:15:09 +01:00
jf-cbd
10fbea5f4d Fix merge conflict 2025-03-24 10:09:33 +01:00
jf-cbd
e49b8fc480 Merge remote-tracking branch 'origin/support/2.7' into support/3.2.1
# Conflicts:
#	core/restservices.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/Form/ObjectFormManager.php
#	lib/composer/autoload_classmap.php
#	lib/composer/autoload_static.php
2025-03-24 10:07:36 +01:00
jf-cbd
4a415fdb59 N°8215 - When PHP warning are enabled, Global Request doesn't work 2025-03-21 14:44:18 +01:00
jf-cbd
5232694c04 N°8281 - Unable to click search button in multiple request template 2025-03-21 11:20:37 +01:00
Eric Espie
2a87d0aa15 N°8242 - When editing a dashboard the parameters do not refresh as expected 2025-03-18 17:40:10 +01:00
Anne-Cath
a103c458cb N°8272 - Portal : Unable to save a date in French format - rollback removed code for N°7145 2025-03-18 16:58:50 +01:00
72 changed files with 1414 additions and 1199 deletions

View File

@@ -93,12 +93,6 @@ gitGraph
checkout support/3.2
commit id: "2024-06-25" tag: "3.2.0-beta1" type: REVERSE
commit id: "2024-08-07" tag: "3.2.0"
checkout support/2.7
commit id: "2025-02-25" tag: "2.7.12"
checkout support/3.1
commit id: "2025-02-25 " tag: "3.1.3"
checkout support/3.2
commit id: "2025-02-25 " tag: "3.2.1"
```
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).

View File

@@ -199,7 +199,7 @@ class DatamodelsXmlFiles extends AbstractGlobFileVersionUpdater
libxml_clear_errors();
$oFileXml->formatOutput = true;
$oFileXml->preserveWhiteSpace = false;
$oFileXml->loadXML($sFileContent);
$oFileXml->loadXML($sFileContent, LIBXML_BIGLINES);
$oFileItopFormat = new iTopDesignFormat($oFileXml);

View File

@@ -106,7 +106,6 @@ We would like to give a special thank you 🤗 to the people from the community
- Raenker, Martin
- Roháč, Richard (a.k.a [@RohacRichard](https://github.com/RohacRichard))
- Rosenke, Stephan
- Rossi, Tommaso (a.k.a [@tomrss](https://www.github.com/tomrss))
- Rudner, Björn (a.k.a [@rudnerbjoern](https://github.com/rudnerbjoern))
- Šafránek, Jaroslav (a.k.a [jkcinik](https://sourceforge.net/u/jkcinik/profile/) on SourceForge)
- Seki, Shoji
@@ -116,7 +115,6 @@ We would like to give a special thank you 🤗 to the people from the community
- Tarjányi, Csaba (a.k.a [@tacsaby](https://github.com/tacsaby))
- Tulio, Marco
- Turrubiates, Miguel
- Vlk, Karel (a.k.a [@vlk-charles](https://www.github.com/vlk-charles))
### Aliases

File diff suppressed because it is too large Load Diff

View File

@@ -347,6 +347,7 @@ EOF
{
$oPage->add('<div class="ui-dialog-header">'.$sIntroduction.'</div>');
}
$oPage->add('<div class="designer-dialog-error"></div>');
$this->Render($oPage);
$oPage->add('</div>');

View File

@@ -90,27 +90,6 @@ class UILinksWidgetDirect
return ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
}
/**
* @param WebPage $oPage
* @param $oValue
* @param $aArgs
* @param $sFormPrefix
* @param $oCurrentObj
* @return BlockIndirectLinkSetEditTable
* @throws ArchivedObjectException
* @throws ConfigException
* @throws CoreException
* @throws CoreUnexpectedValue
* @since 3.2
*/
public function GetBlock(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj)
{
$oBlock = new BlockDirectLinkSetEditTable($this, $this->sInputid);
$oBlock->InitTable($oPage, $oValue, $sFormPrefix, $oCurrentObj);
return $oBlock;
}
/**
* @param WebPage $oPage
* @param string $sProposedRealClass

View File

@@ -148,27 +148,6 @@ class UILinksWidget
return ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
}
/**
* @param WebPage $oPage
* @param $oValue
* @param $aArgs
* @param $sFormPrefix
* @param $oCurrentObj
* @return BlockIndirectLinkSetEditTable
* @throws ArchivedObjectException
* @throws ConfigException
* @throws CoreException
* @throws CoreUnexpectedValue
* @since 3.2
*/
public function GetBlock(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj): BlockIndirectLinkSetEditTable
{
$oBlock = new BlockIndirectLinkSetEditTable($this);
$oBlock->InitTable($oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $this->m_aTableConfig);
return $oBlock;
}
/**
* @param WebPage $oPage
* @param DBObject $oCurrentObj

View File

@@ -4440,7 +4440,7 @@ class AttributeText extends AttributeString
{
// Is there a way to know the current limitation for mysql?
// See mysql_field_len()
return 16383; // number of characters (that can be 1-4 bytes long), not of bytes
return 65535;
}
public static function RenderWikiHtml($sText, $bWikiOnly = false)
@@ -6346,7 +6346,15 @@ class AttributeDateTime extends AttributeDBField
$oFormField = parent::MakeFormField($oObject, $oFormField);
return $oFormField;
// After call to the parent as it sets the current value
$oValue = $oObject->Get($this->GetCode());
if ($oValue === $this->GetNullValue()) {
$oValue = $this->GetDefaultValue($oObject);
}
$oFormField->SetCurrentValue($this->GetFormat()->Format($oValue));
return $oFormField;
}
/**

View File

@@ -611,12 +611,12 @@ class CMDBSource
catch (mysqli_sql_exception $e)
{
self::LogDeadLock($e, true);
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql, $e));
throw new MySQLException('Failed to issue SQL query', ['query' => $sSql, $e, 'stack' => $e->getTraceAsString()]);
} finally {
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
}
if ($oResult === false) {
$aContext = array('query' => $sSql);
$aContext = ["\nstack" => (new Exception(''))->getTraceAsString(), "\nquery" => $sSql];
$iMySqlErrorNo = DbConnectionWrapper::GetDbConnection(true)->errno;
$aMySqlHasGoneAwayErrorCodes = MySQLHasGoneAwayException::getErrorCodes();

View File

@@ -1233,6 +1233,14 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'sessions_tracking.session_handler_extension' => [
'type' => 'string',
'description' => 'to store more data in itop session files, set your own iSessionHandlerExtension implementation class in this variable',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'sessions_tracking.gc_threshold' => [
'type' => 'integer',
'description' => 'fallback in case cron is not active: probability in percent that session files are cleanup during any itop request (100 means always)',

View File

@@ -760,10 +760,10 @@ abstract class DBObject implements iDisplay
*/
public function SetTrim($sAttCode, $sValue)
{
if (!$this->StringFitsInField($sAttCode, $sValue)) {
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
$iMaxSize = $oAttDef->GetMaxSize();
$sLength = mb_strlen($sValue);
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
$iMaxSize = $oAttDef->GetMaxSize();
$sLength = mb_strlen($sValue);
if ($iMaxSize && ($sLength > $iMaxSize)) {
$sMessage = " -truncated ($sLength chars)";
$sValue = mb_substr($sValue, 0, $iMaxSize - mb_strlen($sMessage)).$sMessage;
}
@@ -818,24 +818,6 @@ abstract class DBObject implements iDisplay
$oKPI->ComputeStatsForExtension($this, 'AfterDelete');
}
/**
* @param string $sAttCode
* @param string $sValue
*
* @return bool
* @throws \Exception
*
* @Since 3.2.2
*/
public function StringFitsInField(string $sAttCode, string $sValue): bool
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
$iMaxSize = $oAttDef->GetMaxSize();
$sLength = mb_strlen($sValue);
return !($iMaxSize && ($sLength > $iMaxSize));
}
/**
* Compute (and optionally start) the StopWatches deadlines
*

View File

@@ -71,6 +71,14 @@ class DesignDocument extends DOMDocument
$this->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
}
/**
* @inheritDoc
*/
public function loadXML(string $source, int $options = 0) : bool
{
return parent::loadXML($source, $options | LIBXML_BIGLINES);
}
/**
* Overload of the standard API
*

View File

@@ -6801,12 +6801,14 @@ abstract class MetaModel
if ($bMustBeFound && empty($aRow))
{
$sNotFoundErrorMessage = "No result for the single row query";
IssueLog::Info($sNotFoundErrorMessage, LogChannels::CMDB_SOURCE, [
$e = new CoreException($sNotFoundErrorMessage);
IssueLog::Error($sNotFoundErrorMessage, LogChannels::CMDB_SOURCE, [
'class' => $sClass,
'key' => $iKey,
'sql_query' => $sSQL,
'stack' => $e->getTraceAsString(),
]);
throw new CoreException($sNotFoundErrorMessage);
throw $e;
}
return $aRow;

View File

@@ -1,4 +1,5 @@
{
"name": "combodo/authent-cas",
"config" : {
"classmap-authoritative" : true
},

View File

@@ -4,15 +4,15 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d751713988987e9331980363e24189ce",
"content-hash": "2f342cfe65023402c1e00d88698d52b9",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.1.0"
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View File

@@ -2,6 +2,24 @@
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit1878ad96115c3aa0fa5e9fd9807f5db0::getLoader();
return ComposerAutoloaderInit2f342cfe65023402c1e00d88698d52b9::getLoader();

View File

@@ -42,35 +42,37 @@ namespace Composer\Autoload;
*/
class ClassLoader
{
/** @var ?string */
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
* @var list<string>
*/
private $fallbackDirsPsr0 = array();
@@ -78,8 +80,7 @@ class ClassLoader
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
* @var array<string, string>
*/
private $classMap = array();
@@ -87,29 +88,29 @@ class ClassLoader
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
/** @var string|null */
private $apcuPrefix;
/**
* @var self[]
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return string[]
* @return array<string, list<string>>
*/
public function getPrefixes()
{
@@ -121,8 +122,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
@@ -130,8 +130,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, string>
* @return list<string>
*/
public function getFallbackDirs()
{
@@ -139,8 +138,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, string>
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
@@ -148,8 +146,7 @@ class ClassLoader
}
/**
* @return string[] Array of classname => path
* @psalm-var array<string, string>
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
@@ -157,8 +154,7 @@ class ClassLoader
}
/**
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
@@ -175,24 +171,25 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
$paths
);
}
@@ -201,19 +198,19 @@ class ClassLoader
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
$paths
);
}
}
@@ -222,9 +219,9 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
@@ -232,17 +229,18 @@ class ClassLoader
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@@ -252,18 +250,18 @@ class ClassLoader
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
$paths
);
}
}
@@ -272,8 +270,8 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
@@ -290,8 +288,8 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
@@ -425,7 +423,8 @@ class ClassLoader
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
@@ -476,9 +475,9 @@ class ClassLoader
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return self[]
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
@@ -555,18 +554,26 @@ class ClassLoader
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}

View File

@@ -21,11 +21,31 @@ use Composer\Semver\VersionParser;
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool
*/
private static $installedIsLocalDir;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
@@ -83,7 +103,7 @@ class InstalledVersions
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
@@ -104,7 +124,7 @@ class InstalledVersions
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
@@ -228,7 +248,7 @@ class InstalledVersions
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
@@ -242,7 +262,7 @@ class InstalledVersions
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@@ -265,7 +285,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
@@ -288,17 +308,23 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
// so we have to assume it does not, and that may result in duplicate data being returned when listing
// all installed packages for example
self::$installedIsLocalDir = false;
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
@@ -307,17 +333,27 @@ class InstalledVersions
}
$installed = array();
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = strtr(__DIR__, '\\', '/');
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
self::$installed = $required;
self::$installedIsLocalDir = true;
}
}
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
$copiedLocalDir = true;
}
}
}
@@ -325,12 +361,17 @@ class InstalledVersions
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
if (self::$installed !== array() && !$copiedLocalDir) {
$installed[] = self::$installed;
}
return $installed;
}

View File

@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit1878ad96115c3aa0fa5e9fd9807f5db0
class ComposerAutoloaderInit2f342cfe65023402c1e00d88698d52b9
{
private static $loader;
@@ -22,21 +22,12 @@ class ComposerAutoloaderInit1878ad96115c3aa0fa5e9fd9807f5db0
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit1878ad96115c3aa0fa5e9fd9807f5db0', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit1878ad96115c3aa0fa5e9fd9807f5db0', 'loadClassLoader'));
spl_autoload_register(array('ComposerAutoloaderInit2f342cfe65023402c1e00d88698d52b9', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit2f342cfe65023402c1e00d88698d52b9', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0::getInitializer($loader));
} else {
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit2f342cfe65023402c1e00d88698d52b9::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);

View File

@@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0
class ComposerStaticInit2f342cfe65023402c1e00d88698d52b9
{
public static $prefixLengthsPsr4 = array (
'C' =>
@@ -31,9 +31,9 @@ class ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInit2f342cfe65023402c1e00d88698d52b9::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit2f342cfe65023402c1e00d88698d52b9::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit2f342cfe65023402c1e00d88698d52b9::$classMap;
}, null, ClassLoader::class);
}

View File

@@ -1,22 +1,22 @@
<?php return array(
'root' => array(
'name' => 'combodo/authent-cas',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '567bdc4200f5edb335a39c4b48fbd18bacb6cfc7',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '5a1627632aa2e605996c1c556c60c2a2cddc0a05',
'name' => '__root__',
'dev' => true,
),
'versions' => array(
'__root__' => array(
'combodo/authent-cas' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '567bdc4200f5edb335a39c4b48fbd18bacb6cfc7',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '5a1627632aa2e605996c1c556c60c2a2cddc0a05',
'dev_requirement' => false,
),
),

View File

@@ -1,4 +1,5 @@
{
"name": "combodo/itop-attachments",
"config" : {
"classmap-authoritative" : true
},

View File

@@ -4,15 +4,15 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d751713988987e9331980363e24189ce",
"content-hash": "ee10bebff75617dbf9d929ac6e40c19f",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.1.0"
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View File

@@ -2,6 +2,24 @@
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit478f6fa51842c80229f6a5c4f2ecbd50::getLoader();
return ComposerAutoloaderInitee10bebff75617dbf9d929ac6e40c19f::getLoader();

View File

@@ -42,35 +42,37 @@ namespace Composer\Autoload;
*/
class ClassLoader
{
/** @var ?string */
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
* @var list<string>
*/
private $fallbackDirsPsr0 = array();
@@ -78,8 +80,7 @@ class ClassLoader
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
* @var array<string, string>
*/
private $classMap = array();
@@ -87,29 +88,29 @@ class ClassLoader
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
/** @var string|null */
private $apcuPrefix;
/**
* @var self[]
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return string[]
* @return array<string, list<string>>
*/
public function getPrefixes()
{
@@ -121,8 +122,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
@@ -130,8 +130,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, string>
* @return list<string>
*/
public function getFallbackDirs()
{
@@ -139,8 +138,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, string>
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
@@ -148,8 +146,7 @@ class ClassLoader
}
/**
* @return string[] Array of classname => path
* @psalm-var array<string, string>
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
@@ -157,8 +154,7 @@ class ClassLoader
}
/**
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
@@ -175,24 +171,25 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
$paths
);
}
@@ -201,19 +198,19 @@ class ClassLoader
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
$paths
);
}
}
@@ -222,9 +219,9 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
@@ -232,17 +229,18 @@ class ClassLoader
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@@ -252,18 +250,18 @@ class ClassLoader
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
$paths
);
}
}
@@ -272,8 +270,8 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
@@ -290,8 +288,8 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
@@ -425,7 +423,8 @@ class ClassLoader
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
@@ -476,9 +475,9 @@ class ClassLoader
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return self[]
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
@@ -555,18 +554,26 @@ class ClassLoader
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}

View File

@@ -21,15 +21,22 @@ use Composer\Semver\VersionParser;
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool
*/
private static $installedIsLocalDir;
/**
* @var bool|null
*/
@@ -37,7 +44,7 @@ class InstalledVersions
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
@@ -96,7 +103,7 @@ class InstalledVersions
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
@@ -117,7 +124,7 @@ class InstalledVersions
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
@@ -241,7 +248,7 @@ class InstalledVersions
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
@@ -255,7 +262,7 @@ class InstalledVersions
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@@ -278,7 +285,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
@@ -301,17 +308,23 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
// so we have to assume it does not, and that may result in duplicate data being returned when listing
// all installed packages for example
self::$installedIsLocalDir = false;
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
@@ -320,17 +333,27 @@ class InstalledVersions
}
$installed = array();
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = strtr(__DIR__, '\\', '/');
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
self::$installed = $required;
self::$installedIsLocalDir = true;
}
}
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
$copiedLocalDir = true;
}
}
}
@@ -338,12 +361,17 @@ class InstalledVersions
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
if (self::$installed !== array() && !$copiedLocalDir) {
$installed[] = self::$installed;
}
return $installed;
}

View File

@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit478f6fa51842c80229f6a5c4f2ecbd50
class ComposerAutoloaderInitee10bebff75617dbf9d929ac6e40c19f
{
private static $loader;
@@ -22,21 +22,12 @@ class ComposerAutoloaderInit478f6fa51842c80229f6a5c4f2ecbd50
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit478f6fa51842c80229f6a5c4f2ecbd50', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit478f6fa51842c80229f6a5c4f2ecbd50', 'loadClassLoader'));
spl_autoload_register(array('ComposerAutoloaderInitee10bebff75617dbf9d929ac6e40c19f', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitee10bebff75617dbf9d929ac6e40c19f', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit478f6fa51842c80229f6a5c4f2ecbd50::getInitializer($loader));
} else {
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitee10bebff75617dbf9d929ac6e40c19f::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);

View File

@@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInit478f6fa51842c80229f6a5c4f2ecbd50
class ComposerStaticInitee10bebff75617dbf9d929ac6e40c19f
{
public static $prefixLengthsPsr4 = array (
'C' =>
@@ -28,9 +28,9 @@ class ComposerStaticInit478f6fa51842c80229f6a5c4f2ecbd50
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit478f6fa51842c80229f6a5c4f2ecbd50::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit478f6fa51842c80229f6a5c4f2ecbd50::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit478f6fa51842c80229f6a5c4f2ecbd50::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInitee10bebff75617dbf9d929ac6e40c19f::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitee10bebff75617dbf9d929ac6e40c19f::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitee10bebff75617dbf9d929ac6e40c19f::$classMap;
}, null, ClassLoader::class);
}

View File

@@ -1,22 +1,22 @@
<?php return array(
'root' => array(
'name' => 'combodo/itop-attachments',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => 'd9ea2d27026782c29be93eb9d14ebb636e8e2484',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'cd585f68391ccb113ec98bf911ff6b5ebf979d8b',
'name' => '__root__',
'dev' => true,
),
'versions' => array(
'__root__' => array(
'combodo/itop-attachments' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => 'd9ea2d27026782c29be93eb9d14ebb636e8e2484',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'cd585f68391ccb113ec98bf911ff6b5ebf979d8b',
'dev_requirement' => false,
),
),

View File

@@ -2,6 +2,24 @@
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitd52424b43ff18219f2ec935428aff074::getLoader();
return ComposerAutoloaderInit285a4d33f818950c151bb893193d2cce::getLoader();

View File

@@ -42,35 +42,37 @@ namespace Composer\Autoload;
*/
class ClassLoader
{
/** @var ?string */
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
* @var list<string>
*/
private $fallbackDirsPsr0 = array();
@@ -78,8 +80,7 @@ class ClassLoader
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
* @var array<string, string>
*/
private $classMap = array();
@@ -87,29 +88,29 @@ class ClassLoader
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
/** @var string|null */
private $apcuPrefix;
/**
* @var self[]
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return string[]
* @return array<string, list<string>>
*/
public function getPrefixes()
{
@@ -121,8 +122,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
@@ -130,8 +130,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, string>
* @return list<string>
*/
public function getFallbackDirs()
{
@@ -139,8 +138,7 @@ class ClassLoader
}
/**
* @return array[]
* @psalm-return array<string, string>
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
@@ -148,8 +146,7 @@ class ClassLoader
}
/**
* @return string[] Array of classname => path
* @psalm-var array<string, string>
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
@@ -157,8 +154,7 @@ class ClassLoader
}
/**
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
@@ -175,24 +171,25 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
$paths
);
}
@@ -201,19 +198,19 @@ class ClassLoader
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
$paths
);
}
}
@@ -222,9 +219,9 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
@@ -232,17 +229,18 @@ class ClassLoader
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@@ -252,18 +250,18 @@ class ClassLoader
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
$paths
);
}
}
@@ -272,8 +270,8 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
@@ -290,8 +288,8 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
@@ -425,7 +423,8 @@ class ClassLoader
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
@@ -476,9 +475,9 @@ class ClassLoader
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return self[]
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
@@ -555,18 +554,26 @@ class ClassLoader
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}

View File

@@ -21,11 +21,31 @@ use Composer\Semver\VersionParser;
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool
*/
private static $installedIsLocalDir;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
@@ -83,7 +103,7 @@ class InstalledVersions
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
@@ -104,7 +124,7 @@ class InstalledVersions
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
@@ -228,7 +248,7 @@ class InstalledVersions
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
@@ -242,7 +262,7 @@ class InstalledVersions
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@@ -265,7 +285,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
@@ -288,17 +308,23 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
// so we have to assume it does not, and that may result in duplicate data being returned when listing
// all installed packages for example
self::$installedIsLocalDir = false;
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
@@ -307,17 +333,27 @@ class InstalledVersions
}
$installed = array();
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = strtr(__DIR__, '\\', '/');
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
self::$installed = $required;
self::$installedIsLocalDir = true;
}
}
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
$copiedLocalDir = true;
}
}
}
@@ -325,12 +361,17 @@ class InstalledVersions
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
if (self::$installed !== array() && !$copiedLocalDir) {
$installed[] = self::$installed;
}
return $installed;
}

View File

@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitd52424b43ff18219f2ec935428aff074
class ComposerAutoloaderInit285a4d33f818950c151bb893193d2cce
{
private static $loader;
@@ -22,21 +22,12 @@ class ComposerAutoloaderInitd52424b43ff18219f2ec935428aff074
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitd52424b43ff18219f2ec935428aff074', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInitd52424b43ff18219f2ec935428aff074', 'loadClassLoader'));
spl_autoload_register(array('ComposerAutoloaderInit285a4d33f818950c151bb893193d2cce', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit285a4d33f818950c151bb893193d2cce', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitd52424b43ff18219f2ec935428aff074::getInitializer($loader));
} else {
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit285a4d33f818950c151bb893193d2cce::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);

View File

@@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInitd52424b43ff18219f2ec935428aff074
class ComposerStaticInit285a4d33f818950c151bb893193d2cce
{
public static $prefixLengthsPsr4 = array (
'C' =>
@@ -31,9 +31,9 @@ class ComposerStaticInitd52424b43ff18219f2ec935428aff074
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitd52424b43ff18219f2ec935428aff074::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitd52424b43ff18219f2ec935428aff074::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitd52424b43ff18219f2ec935428aff074::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInit285a4d33f818950c151bb893193d2cce::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit285a4d33f818950c151bb893193d2cce::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit285a4d33f818950c151bb893193d2cce::$classMap;
}, null, ClassLoader::class);
}

View File

@@ -1,22 +1,22 @@
<?php return array(
'root' => array(
'name' => 'combodo/itop-oauth-client',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '567bdc4200f5edb335a39c4b48fbd18bacb6cfc7',
'type' => 'itop-extension',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '8db89c3d5f5f88d80780db8acb5147ba0d95c42f',
'name' => 'combodo/itop-oauth-client',
'dev' => true,
),
'versions' => array(
'combodo/itop-oauth-client' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '567bdc4200f5edb335a39c4b48fbd18bacb6cfc7',
'type' => 'itop-extension',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '8db89c3d5f5f88d80780db8acb5147ba0d95c42f',
'dev_requirement' => false,
),
),

View File

@@ -1,5 +1,8 @@
{
"license": "AGPLv3",
"license": "AGPLv3",
"config" : {
"autoloader-suffix": "Combodo_ItopPortalBase_Portal"
},
"autoload": {
"psr-4": {
"Combodo\\iTop\\Portal\\": "src/"

View File

@@ -1238,15 +1238,17 @@ class ObjectFormManager extends FormManager
foreach ($aCurrentValues as $sAttCode => $value)
{
if (!array_key_exists($sAttCode, $this->aFieldsAtts)) {
continue;
}
$iAttributeFlags = $this->aFieldsAtts[$sAttCode];
if ($iAttributeFlags & OPT_ATT_HIDDEN) {
continue;
}
if ($iAttributeFlags & OPT_ATT_READONLY) {
continue;
if (count($this->aFieldsAtts) !== 0) {
if (!array_key_exists($sAttCode, $this->aFieldsAtts)) {
continue;
}
$iAttributeFlags = $this->aFieldsAtts[$sAttCode];
if ($iAttributeFlags & OPT_ATT_HIDDEN) {
continue;
}
if ($iAttributeFlags & OPT_ATT_READONLY) {
continue;
}
}
if (MetaModel::IsValidAttCode($sObjectClass, $sAttCode)) {

View File

@@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitd751713988987e9331980363e24189ce::getLoader();
return ComposerAutoloaderInitCombodo_ItopPortalBase_Portal::getLoader();

View File

@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitd751713988987e9331980363e24189ce
class ComposerAutoloaderInitCombodo_ItopPortalBase_Portal
{
private static $loader;
@@ -22,13 +22,14 @@ class ComposerAutoloaderInitd751713988987e9331980363e24189ce
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitd751713988987e9331980363e24189ce', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInitCombodo_ItopPortalBase_Portal', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitd751713988987e9331980363e24189ce', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInitCombodo_ItopPortalBase_Portal', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitd751713988987e9331980363e24189ce::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInitCombodo_ItopPortalBase_Portal::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
return $loader;

View File

@@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInitd751713988987e9331980363e24189ce
class ComposerStaticInitCombodo_ItopPortalBase_Portal
{
public static $prefixLengthsPsr4 = array (
'C' =>
@@ -103,9 +103,9 @@ class ComposerStaticInitd751713988987e9331980363e24189ce
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitd751713988987e9331980363e24189ce::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitd751713988987e9331980363e24189ce::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitd751713988987e9331980363e24189ce::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInitCombodo_ItopPortalBase_Portal::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitCombodo_ItopPortalBase_Portal::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitCombodo_ItopPortalBase_Portal::$classMap;
}, null, ClassLoader::class);
}

View File

@@ -390,16 +390,17 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH
this.RegisterChange = function () {
// Listen only used inputs
$('#linkedset_'+me.id+' :input[name^="attr_'+me.sAttCode+'["]').off('change').on('change', function () {
$('body').off('change', '#linkedset_'+me.id+' :input[name^="attr_'+me.sAttCode+'["]')
.on('change', '#linkedset_'+me.id+' :input[name^="attr_'+me.sAttCode+'["]', function () {
if (!($(this).hasClass('selection')))
{
let oCheckbox = $(this).closest('tr').find('.selection');
let iLink = oCheckbox.attr('data-link-id');
let iUniqueId = oCheckbox.attr('data-unique-id');
let sAttCode = $(this).closest('.attribute-edit').attr('data-attcode');
let value = $(this).val();;
return me.OnValueChange(iLink, iUniqueId, sAttCode, value, this);
}
{
let oCheckbox = $(this).closest('tr').find('.selection');
let iLink = oCheckbox.attr('data-link-id');
let iUniqueId = oCheckbox.attr('data-unique-id');
let sAttCode = $(this).closest('.attribute-edit').attr('data-attcode');
let value = $(this).val();;
return me.OnValueChange(iLink, iUniqueId, sAttCode, value, this);
}
return true;
});
};

View File

@@ -548,6 +548,7 @@ function ValidateWithPattern(sFieldId, bMandatory, sPattern, sFormId, aForbidden
if (sMessage)
{
$('#'+sFieldId).attr('data-tooltip-content', sMessage);
$('#'+sFieldId).attr('data-tooltip-theme', 'error');
CombodoTooltip.InitTooltipFromMarkup($('#'+sFieldId), true);
$('#'+sFieldId)[0]._tippy.show();
}

View File

@@ -525,6 +525,7 @@ return array(
'Combodo\\iTop\\Service\\TemporaryObjects\\TemporaryObjectsEvents' => $baseDir . '/sources/Service/TemporaryObjects/TemporaryObjectsEvents.php',
'Combodo\\iTop\\SessionTracker\\SessionGC' => $baseDir . '/sources/SessionTracker/SessionGC.php',
'Combodo\\iTop\\SessionTracker\\SessionHandler' => $baseDir . '/sources/SessionTracker/SessionHandler.php',
'Combodo\\iTop\\SessionTracker\\iSessionHandlerExtension' => $baseDir . '/sources/SessionTracker/iSessionHandlerExtension.php',
'CompileCSSService' => $baseDir . '/application/compilecssservice.class.inc.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'Config' => $baseDir . '/core/config.class.inc.php',
@@ -3230,5 +3231,5 @@ return array(
'privUITransactionFile' => $baseDir . '/application/transaction.class.inc.php',
'privUITransactionSession' => $baseDir . '/application/transaction.class.inc.php',
'utils' => $baseDir . '/application/utils.inc.php',
'<EFBFBD>' => $vendorDir . '/symfony/cache/Traits/ValueWrapper.php',
'©' => $vendorDir . '/symfony/cache/Traits/ValueWrapper.php',
);

View File

@@ -915,6 +915,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Service\\TemporaryObjects\\TemporaryObjectsEvents' => __DIR__ . '/../..' . '/sources/Service/TemporaryObjects/TemporaryObjectsEvents.php',
'Combodo\\iTop\\SessionTracker\\SessionGC' => __DIR__ . '/../..' . '/sources/SessionTracker/SessionGC.php',
'Combodo\\iTop\\SessionTracker\\SessionHandler' => __DIR__ . '/../..' . '/sources/SessionTracker/SessionHandler.php',
'Combodo\\iTop\\SessionTracker\\iSessionHandlerExtension' => __DIR__ . '/../..' . '/sources/SessionTracker/iSessionHandlerExtension.php',
'CompileCSSService' => __DIR__ . '/../..' . '/application/compilecssservice.class.inc.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'Config' => __DIR__ . '/../..' . '/core/config.class.inc.php',
@@ -3620,7 +3621,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'privUITransactionFile' => __DIR__ . '/../..' . '/application/transaction.class.inc.php',
'privUITransactionSession' => __DIR__ . '/../..' . '/application/transaction.class.inc.php',
'utils' => __DIR__ . '/../..' . '/application/utils.inc.php',
'<EFBFBD>' => __DIR__ . '/..' . '/symfony/cache/Traits/ValueWrapper.php',
'©' => __DIR__ . '/..' . '/symfony/cache/Traits/ValueWrapper.php',
);
public static function getInitializer(ClassLoader $loader)

View File

@@ -69,14 +69,37 @@ class MFException extends Exception
* MFException constructor.
*
* @inheritDoc
*
* @param string $message
* @param int $code: error code
* @param DesignElement $oNode: dom node
* @param string|null $sXPath: XML xpath: if provided used in exception message. otherwise computed via $oNode
* @param string $sExtraInfo: additional information stored in exception
* @param DesignElement|null $oParentFallbackNode: fallback dom node (usually parent). in case $oNode XML line is wrong (set to 0), line number computed/displayed in error message comes from $oParentFallbackNode
*/
public function __construct($message = null, $code = null, $iSourceLineNumber = 0, $sXPath = '', $sExtraInfo = '', $previous = null)
public function __construct(string $message, int $code, DesignElement $oNode, ?string $sXPath = null, string $sExtraInfo = '', ?DesignElement $oParentFallbackNode = null)
{
parent::__construct($message, $code, $previous);
$iSourceLineNumber = ModelFactory::GetXMLLineNumber($oNode);
if ($iSourceLineNumber==0 && ! is_null($oParentFallbackNode)){
$iSourceLineNumber = ModelFactory::GetXMLLineNumber($oParentFallbackNode);
}
if (is_null($sXPath)){
$sXPath = DesignDocument::GetItopNodePath($oNode);
}
$this->iSourceLineNumber = $iSourceLineNumber;
$this->iSourceLineOffset = 0;
$this->sXPath = $sXPath;
$this->sExtraInfo = $sExtraInfo;
parent::__construct("$sXPath at line $iSourceLineNumber: $message", $code);
$aContext = [
'error' => $code,
'stack' => $this->getTraceAsString(),
'extra_info' => $sExtraInfo,
];
\IssueLog::Error($this->getMessage(), null, $aContext);
}
/**
@@ -196,6 +219,10 @@ class MFModule
return;
}
if (!is_dir($sRootDir)) {
$sRootDir = APPROOT.$sRootDir;
}
// Scan the module's root directory to find the datamodel(*).xml files
if ($hDir = opendir($sRootDir))
{
@@ -749,10 +776,7 @@ class ModelFactory
case 'define_if_not_exists':
/** @var \MFElement $oParentNode */
$oParentNode = $oSubClassNode->parentNode;
$iLine = ModelFactory::GetXMLLineNumber($oParentNode);
$sItopNodePath = DesignDocument::GetItopNodePath($oParentNode);
throw new MFException("$sItopNodePath at line $iLine: _delta=\"$sParentDeltaSpec\" not supported for classes in hierarchy",
MFException::NOT_FOUND, $iLine, $sItopNodePath);
throw new MFException("_delta=\"$sParentDeltaSpec\" not supported for classes in hierarchy", MFException::NOT_FOUND, $oParentNode);
}
}
@@ -808,10 +832,7 @@ class ModelFactory
// Move class after new parent class (before its next sibling)
$oNodeForTargetParent = $oTargetDocument->GetNodes("/itop_design/classes/class[@id=\"$sParentClassName\"]")->item(0);
if (is_null($oNodeForTargetParent)) {
$iLine = ModelFactory::GetXMLLineNumber($oSourceParentClassNode);
$sItopNodePath = DesignDocument::GetItopNodePath($oSourceParentClassNode);
throw new MFException($sItopNodePath." at line $iLine: invalid parent class '$sParentClassName'",
MFException::NOT_FOUND, $iLine, $sItopNodePath);
throw new MFException("invalid parent class '$sParentClassName'", MFException::NOT_FOUND, $oSourceParentClassNode);
}
$oNextParentSibling = $oNodeForTargetParent->nextSibling;
if ($oNextParentSibling) {
@@ -839,20 +860,14 @@ class ModelFactory
if (!$oTargetNode || $oTargetNode->IsRemoved()) {
// The node does not exist or is marked as removed
if ($bMustExist) {
$iLine = ModelFactory::GetXMLLineNumber($oSourceNode);
$sItopNodePath = DesignDocument::GetItopNodePath($oSourceNode);
throw new MFException($sItopNodePath.' at line '.$iLine.': could not be found or marked as removed',
MFException::NOT_FOUND, $iLine, $sItopNodePath);
throw new MFException("could not be found or marked as removed", MFException::NOT_FOUND, $oSourceNode);
}
if ($bIfExists) {
// Do not continue deeper
$oTargetNode = null;
} else {
if (!$bSpecifiedMerge && $sMode === self::LOAD_DELTA_MODE_STRICT && ($sSearchId !== '' || is_null($oSourceNode->GetFirstElementChild()))) {
$iLine = ModelFactory::GetXMLLineNumber($oSourceNode);
$sItopNodePath = DesignDocument::GetItopNodePath($oSourceNode);
throw new MFException($sItopNodePath.' at line '.$iLine.': could not be found or marked as removed (strict mode)',
MFException::NOT_FOUND, $iLine, $sItopNodePath, 'strict mode');
throw new MFException("could not be found or marked as removed (strict mode)", MFException::NOT_FOUND, $oSourceNode, null, 'strict mode');
}
// Ignore renaming non-existant node
@@ -901,10 +916,7 @@ class ModelFactory
if (is_null($oSourceNode->GetFirstElementChild()) && $oTargetParentNode instanceof MFElement) {
// Leaf node
if ($sMode === self::LOAD_DELTA_MODE_STRICT && !$oSourceNode->hasAttribute('_rename_from') && trim($oSourceNode->GetText('')) !== '') {
$iLine = ModelFactory::GetXMLLineNumber($oSourceNode);
$sItopNodePath = DesignDocument::GetItopNodePath($oSourceNode);
throw new MFException($sItopNodePath.' at line '.$iLine.': cannot be modified without _delta flag (strict mode)',
MFException::AMBIGUOUS_LEAF, $iLine, $sItopNodePath, 'strict mode');
throw new MFException("cannot be modified without _delta flag (strict mode)", MFException::AMBIGUOUS_LEAF, $oSourceNode, null, 'strict mode');
} else {
// Lax mode: same as redefine
// Replace the existing node by the given node - copy child nodes as well
@@ -912,7 +924,7 @@ class ModelFactory
if (trim($oSourceNode->GetText('')) !== '') {
$oTargetNode = $oTargetDocument->importNode($oSourceNode, true);
$sSearchId = $oSourceNode->hasAttribute('_rename_from') ? $oSourceNode->getAttribute('_rename_from') : $oSourceNode->getAttribute('id');
$oTargetParentNode->RedefineChildNode($oTargetNode, $sSearchId);
$oTargetParentNode->RedefineChildNode($oTargetNode, $sSearchId, $oSourceNode);
}
}
} else {
@@ -956,7 +968,7 @@ class ModelFactory
// Replace the existing node by the given node - copy child nodes as well
/** @var \MFElement $oTargetNode */
$oTargetNode = $oTargetDocument->importNode($oSourceNode, true);
$oTargetParentNode->RedefineChildNode($oTargetNode, $sSearchId);
$oTargetParentNode->RedefineChildNode($oTargetNode, $sSearchId, $oSourceNode);
break;
case 'delete_if_exists':
@@ -976,25 +988,18 @@ class ModelFactory
case 'delete':
/** @var \MFElement $oTargetNode */
$oTargetNode = $oTargetParentNode->_FindChildNode($oSourceNode, $sSearchId);
$sPath = MFDocument::GetItopNodePath($oSourceNode);
$iLine = $this->GetXMLLineNumber($oSourceNode);
if ($oTargetNode == null) {
throw new MFException($sPath.' at line '.$iLine.": could not be deleted (not found)", MFException::COULD_NOT_BE_DELETED,
$iLine, $sPath);
throw new MFException("could not be deleted (not found)", MFException::COULD_NOT_BE_DELETED, $oSourceNode);
}
if ($oTargetNode->IsRemoved()) {
throw new MFException($sPath.' at line '.$iLine.": could not be deleted (already marked as deleted)",
MFException::ALREADY_DELETED, $iLine, $sPath);
throw new MFException("could not be deleted (already marked as deleted)", MFException::ALREADY_DELETED, $oSourceNode);
}
$oTargetNode->Delete();
break;
default:
$sPath = MFDocument::GetItopNodePath($oSourceNode);
$iLine = $this->GetXMLLineNumber($oSourceNode);
throw new MFException($sPath.' at line '.$iLine.": unexpected value for attribute _delta: '".$sDeltaSpec."'",
MFException::INVALID_DELTA, $iLine, $sPath, $sDeltaSpec);
throw new MFException("unexpected value for attribute _delta: '".$sDeltaSpec."'", MFException::INVALID_DELTA, $oSourceNode, null, $sDeltaSpec);
}
if ($oTargetNode && $oTargetNode->parentNode) {
@@ -2124,7 +2129,7 @@ class MFElement extends Combodo\iTop\DesignElement
*/
public function IsInDefinition()
{
// Iterate through the parents: reset the flag if any of them has a flag set
// Iterate through the parents: reset the flag if any of them has a flag set
for ($oParent = $this; $oParent instanceof MFElement; $oParent = $oParent->parentNode)
{
if ($oParent->GetAlteration() != '')
@@ -2201,14 +2206,12 @@ class MFElement extends Combodo\iTop\DesignElement
if ($oExisting)
{
if (!$oExisting->IsRemoved()) {
$sPath = MFDocument::GetItopNodePath($oNode);
$iLine = ModelFactory::GetXMLLineNumber($oNode);
$sExistingPath = MFDocument::GetItopNodePath($oExisting).' created_in: ['.$oExisting->getAttribute('_created_in').']';
$iExistingLine = ModelFactory::GetXMLLineNumber($oExisting);
$sExceptionMessage = <<<EOF
`{$sPath}` at line {$iLine} could not be added : already exists in `{$sExistingPath}` at line {$iExistingLine}
could not be added : already exists in `{$sExistingPath}` at line {$iExistingLine}
EOF;
throw new MFException($sExceptionMessage, MFException::COULD_NOT_BE_ADDED, $iLine, $sPath);
throw new MFException($sExceptionMessage, MFException::COULD_NOT_BE_ADDED, $oNode);
}
$oExisting->ReplaceWithSingleNode($oNode);
$sFlag = 'replaced';
@@ -2229,13 +2232,14 @@ EOF;
*
* @param MFElement $oNode The node (including all subnodes) to set
* @param string|null $sSearchId
* @param mixed $oParentFallbackNode: provided to print accurate line number in case $oNode line is 0
*
* @return void
*
* @throws MFException
* @throws \Exception
*/
public function RedefineChildNode(MFElement $oNode, $sSearchId = null)
public function RedefineChildNode(MFElement $oNode, $sSearchId = null, $oParentFallbackNode=null)
{
// First: cleanup any flag behind the new node, and eventually add trace data
$oNode->ApplyChanges();
@@ -2245,17 +2249,13 @@ EOF;
if (!$oExisting)
{
$sPath = MFDocument::GetItopNodePath($this)."/".$oNode->tagName.(empty($sSearchId) ? '' : "[$sSearchId]");
$iLine = ModelFactory::GetXMLLineNumber($oNode);
throw new MFException($sPath." at line $iLine: could not be modified (not found)", MFException::COULD_NOT_BE_MODIFIED_NOT_FOUND,
$sPath, $iLine);
throw new MFException('could not be modified (not found)', MFException::COULD_NOT_BE_MODIFIED_NOT_FOUND, $oNode, $sPath, '', $oParentFallbackNode);
}
$sPrevFlag = $oExisting->GetAlteration();
$sOldId = $oExisting->getAttribute('_old_id');
if ($oExisting->IsRemoved()) {
$sPath = MFDocument::GetItopNodePath($this)."/".$oNode->tagName.(empty($sSearchId) ? '' : "[$sSearchId]");
$iLine = ModelFactory::GetXMLLineNumber($oNode);
throw new MFException($sPath." at line $iLine: could not be modified (marked as deleted)",
MFException::COULD_NOT_BE_MODIFIED_ALREADY_DELETED, $sPath, $iLine);
throw new MFException('could not be modified (marked as deleted)', MFException::COULD_NOT_BE_MODIFIED_ALREADY_DELETED, $oNode, $sPath, '', $oParentFallbackNode);
}
$oExisting->ReplaceWithSingleNode($oNode);
if (!$this->IsInDefinition()) {

View File

@@ -120,10 +120,6 @@ class ModuleDiscovery
$aArgs['module_file'] = $sFilePath;
list($sModuleName, $sModuleVersion) = static::GetModuleName($sId);
if ($sModuleVersion == '')
{
$sModuleVersion = '1.0.0';
}
if (array_key_exists($sModuleName, self::$m_aModuleVersionByName))
{
@@ -233,7 +229,7 @@ class ModuleDiscovery
}
ksort($aDependencies);
$aOrderedModules = [];
$iLoopCount = 1;
$iLoopCount = 0;
while(($iLoopCount < count($aModules)) && (count($aDependencies) > 0) )
{
foreach($aDependencies as $sId => $aRemainingDeps)
@@ -308,16 +304,8 @@ class ModuleDiscovery
// Separate the module names from their version for an easier comparison later
foreach($aOrderedModules as $sModuleId)
{
$aMatches = array();
if (preg_match('|^([^/]+)/(.*)$|', $sModuleId, $aMatches))
{
$aModuleVersions[$aMatches[1]] = $aMatches[2];
}
else
{
// No version number found, assume 1.0.0
$aModuleVersions[$sModuleId] = '1.0.0';
}
list($sModuleName, $sVersion) = self::GetModuleName($sModuleId);
$aModuleVersions[$sModuleName] = $sVersion;
}
if (preg_match_all('/([^\(\)&| ]+)/', $sDepString, $aMatches))
{
@@ -456,13 +444,17 @@ class ModuleDiscovery
{
$sName = $aMatches[1];
$sVersion = $aMatches[2];
if ($sVersion === ""){
$sVersion = "1.0.0";
}
}
else
{
$sName = $sModuleId;
$sVersion = "";
$sVersion = "1.0.0";
}
return array($sName, $sVersion);
return [$sName, $sVersion];
}
/**

View File

@@ -143,8 +143,6 @@ $sDBUser = $aDBXmlSettings['user'];
$sDBPwd = $aDBXmlSettings['pwd'];
$sDBName = $aDBXmlSettings['name'];
$sDBPrefix = $aDBXmlSettings['prefix'];
$bDBTlsEnabled = $aDBXmlSettings['db_tls_enabled'];
$sDBTlsCa = $aDBXmlSettings['db_tls_ca'];
if ($sMode == 'install')
{
@@ -221,10 +219,13 @@ if ($sMode == 'install')
die("Cleanup not implemented for a partial database (prefix= '$sDBPrefix')\nExiting.");
}
try
$oMysqli = new mysqli($sDBServer, $sDBUser, $sDBPwd);
if ($oMysqli->connect_errno)
{
die("Cannot connect to the MySQL server (".$oMysqli->connect_errno . ") ".$oMysqli->connect_error."\nExiting");
}
else
{
$oMysqli = CMDBSource::GetMysqliInstance($sDBServer, $sDBUser, $sDBPwd, null, $bDBTlsEnabled, $sDBTlsCa, true);
if ($oMysqli->select_db($sDBName))
{
echo "Deleting database '$sDBName'\n";
@@ -235,10 +236,6 @@ if ($sMode == 'install')
echo "The database '$sDBName' does not seem to exist. Nothing to cleanup.\n";
}
}
catch (MySQLException $e)
{
die($e->getMessage()."\nExiting");
}
}
}
else
@@ -315,9 +312,9 @@ if ($bInstall)
}
else
{
try
$oMysqli = new mysqli($sDBServer, $sDBUser, $sDBPwd);
if (!$oMysqli->connect_errno)
{
$oMysqli = CMDBSource::GetMysqliInstance($sDBServer, $sDBUser, $sDBPwd, null, $bDBTlsEnabled, $sDBTlsCa, true);
if ($oMysqli->select_db($sDBName))
{
// Check the presence of a table to record information about the MTP (from the Designer)
@@ -360,10 +357,6 @@ if ($bInstall)
}
}
}
catch (MySQLException $e)
{
// Continue anyway
}
}
}
else

View File

@@ -773,7 +773,7 @@ abstract class Controller extends AbstractController
{
// iTop 3.1 and older compatibility, if not an URI we don't know if its relative to app root or module root
if (strpos($sLinkedScript, "://") === false) {
$this->m_oPage->add_linked_script($sLinkedScript);
$this->m_oPage->LinkScriptFromAppRoot(utils::LocalPath($sLinkedScript, APPROOT));
return;
}

View File

@@ -1280,18 +1280,19 @@ JS;
protected function AddCompatibilityFiles(string $sFileType, string $sMode): void
{
$sConstantName = 'COMPATIBILITY_'.strtoupper($sMode).'_LINKED_'. ($sFileType === static::ENUM_COMPATIBILITY_FILE_TYPE_CSS ? 'STYLESHEETS' : 'SCRIPTS') .'_REL_PATH';
$sMethodName = 'add_linked_'.($sFileType === static::ENUM_COMPATIBILITY_FILE_TYPE_CSS ? 'stylesheet' : 'script');
$sMethodName = 'Link'.($sFileType === static::ENUM_COMPATIBILITY_FILE_TYPE_CSS ? 'Resource' : 'Script').'FromAppRoot';
// Add ancestors files
foreach (array_reverse(class_parents(static::class)) as $sParentClass) {
foreach (constant($sParentClass.'::'.$sConstantName) as $sFile) {
$this->$sMethodName(utils::GetAbsoluteUrlAppRoot().$sFile);
$this->$sMethodName($sFile);
}
}
// Add current class files
foreach (constant('static::'.$sConstantName) as $sFile) {
$this->$sMethodName(utils::GetAbsoluteUrlAppRoot().$sFile);
$this->$sMethodName($sFile);
}
}

View File

@@ -664,6 +664,7 @@ JS;
$aResult['data'] = ['error_message' => $e->getHtmlMessage()];
} else {
$oPage->AddHeaderMessage($e->getHtmlMessage(), 'message_error');
$oObj->Reload();
$oObj->DisplayModifyForm($oPage,
array('wizard_container' => true)); // wizard_container: display the wizard border and the title
}

View File

@@ -139,23 +139,59 @@ class SessionHandler extends \SessionHandler
// - Data corruption (not a json / not an array / no previous creation_time key)
$iCreationTime = time();
$aJson=[];
if (! is_null($sPreviousFileVersionContent)) {
$aJson = json_decode($sPreviousFileVersionContent, true);
if (is_array($aJson) && array_key_exists('creation_time', $aJson)) {
$iCreationTime = $aJson['creation_time'];
if (is_array($aJson)){
if (array_key_exists('creation_time', $aJson)) {
$iCreationTime = $aJson['creation_time'];
}
} else {
$aJson=[];
}
}
$aData = [
'login_mode' => Session::Get('login_mode'),
'user_id' => $sUserId,
'creation_time' => $iCreationTime,
'context' => implode('|', ContextTag::GetStack())
];
$oiSessionHandlerExtension = $this->GetSessionHandlerExtension();
if (! is_null($oiSessionHandlerExtension)){
$oiSessionHandlerExtension->CompleteSessionData($aJson, $aData);
}
return json_encode (
[
'login_mode' => Session::Get('login_mode'),
'user_id' => $sUserId,
'creation_time' => $iCreationTime,
'context' => implode('|', ContextTag::GetStack())
]
$aData
);
} catch(Exception $e) {
IssueLog::Error(__METHOD__, null, [ 'error' => $e->getMessage() ]);
}
return null;
}
private function GetSessionHandlerExtension() : ?iSessionHandlerExtension
{
$sSessionHandlerExtensionClass = utils::GetConfig()->Get('sessions_tracking.session_handler_extension');
if (strlen($sSessionHandlerExtensionClass) !=0){
try{
if (! class_exists($sSessionHandlerExtensionClass)){
throw new \Exception("Cannot find class");
}
/** @var iSessionHandlerExtension $oSessionHandlerExtension */
$oSessionHandlerExtension = new $sSessionHandlerExtensionClass;
if ($oSessionHandlerExtension instanceof iSessionHandlerExtension){
return $oSessionHandlerExtension;
}
throw new \Exception("Not an instance of iSessionHandlerExtension");
} catch(\Exception $e) {
IssueLog::Error(__METHOD__ . ': cannot instanciate iSessionHandlerExtension', null, ['sessions_tracking.session_handler_extension' => $sSessionHandlerExtensionClass]);
}
}
return null;

View File

@@ -0,0 +1,16 @@
<?php
namespace Combodo\iTop\SessionTracker;
interface iSessionHandlerExtension {
public function __construct();
/**
* Called by SessionHandler to change data stored in iTop session files
* @param array $aJson: previous data stored in session file
* @param array $aData: usual session data see @SessionHandler
*
* @return void
*/
public function CompleteSessionData(array $aJson, array &$aData) : void;
}

View File

@@ -2440,7 +2440,9 @@ class SynchroReplica extends DBObject implements iDisplay
// Really modified ?
if ($oDestObj->IsModified())
{
$oDestObj::SetCurrentChange($oChange);
if(method_exists(get_class($oDestObj), "SetCurrentChange")){
$oDestObj::SetCurrentChange($oChange);
}
$oDestObj->DBUpdate();
$bModified = true;
$oStatLog->AddTrace('Updated object - Values: {'.implode(', ', $aValueTrace).'}', $this);
@@ -2499,7 +2501,10 @@ class SynchroReplica extends DBObject implements iDisplay
$aValueTrace[] = "$sAttCode: $value";
}
}
$oDestObj::SetCurrentChange($oChange);
if(method_exists(get_class($oDestObj), "SetCurrentChange")){
$oDestObj::SetCurrentChange($oChange);
}
$iNew = $oDestObj->DBInsert();
$this->Set('dest_id', $oDestObj->GetKey());

View File

@@ -179,14 +179,14 @@ abstract class TestHandler
}
catch (CoreException $e)
{
//$this->ReportError($e->getMessage());
//$this->ReportError($e->__tostring());
//$this->ReportErrors($e->getMessage());
//$this->ReportErrors($e->__tostring());
$this->ReportError($e->getMessage().' - '.$e->getTraceAsHtml());
}
catch (Exception $e)
{
//$this->ReportError($e->getMessage());
//$this->ReportError($e->__tostring());
//$this->ReportErrors($e->getMessage());
//$this->ReportErrors($e->__tostring());
$this->ReportError('class '.get_class($e).' --- '.$e->getMessage().' - '.$e->getTraceAsString());
}
restore_error_handler();

View File

@@ -397,7 +397,7 @@ class TestMyBizModel extends TestBizModel
protected function DoExecute()
{
// $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
// $this->ReportErrors("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
// $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
//$this->test_linksinfo();
//$this->test_list_attributes();

View File

@@ -834,7 +834,6 @@ HTML,
'bad context_param' => [utils::ENUM_SANITIZATION_FILTER_CONTEXT_PARAM, '%dssD,25_=%:+-', null],
'good element_identifier' => [utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER, 'AD05nb', 'AD05nb'],
'bad element_identifier' => [utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER, 'AD05nb+', 'AD05nb'],
'array' => [utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER, ['AD05nb+','apply_modify'], ['AD05nb','apply_modify']],
'good url' => [utils::ENUM_SANITIZATION_FILTER_URL, 'https://www.w3schools.com', 'https://www.w3schools.com'],
'bad url' => [utils::ENUM_SANITIZATION_FILTER_URL, 'https://www.w3schoo<6F><6F>ls.co<63>m', null],
'url with injection' => [utils::ENUM_SANITIZATION_FILTER_URL, 'https://demo.combodo.com/simple/pages/UI.php?operation=full_text&text=<img zzz src=x onerror=alert(1) //>', null],

View File

@@ -2,19 +2,11 @@
namespace Combodo\iTop\Test\UnitTest\Core;
use ArchivedObjectException;
use AttributeDate;
use AttributeDateTime;
use Change;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use CoreCannotSaveObjectException;
use CoreException;
use CoreUnexpectedValue;
use CoreWarning;
use EventRestService;
use MetaModel;
use MySQLException;
use OQLException;
use UserRequest;
class AttributeDefinitionTest extends ItopDataTestCase {
@@ -351,23 +343,4 @@ PHP
return $oAttribute;
}
/**
* @throws CoreException
* @throws CoreUnexpectedValue
* @throws OQLException
* @throws ArchivedObjectException
* @throws CoreCannotSaveObjectException
* @throws CoreWarning
* @throws MySQLException
*/
public function testTrimLogOnAttributeText()
{
// will throw MySQLException if GetMaxSize() of AttributeText is incorrect (should be number of bytes, not of characters)
$oLog = new EventRestService();
$sLongString = json_encode(array_fill(0, 5000, 'é😃 '),
JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
$oLog->SetTrim('json_input', $sLongString);
static::assertNotEquals($oLog->Get('json_input'), $sLongString);
static::assertStringContainsString('truncated', $oLog->Get('json_input'));
}
}

View File

@@ -22,7 +22,6 @@ namespace Combodo\iTop\Test\UnitTest\Core;
use Attachment;
use AttributeDateTime;
use Combodo\iTop\Service\Events\EventData;
use EventRestService;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use CoreException;
use DateTime;
@@ -1416,22 +1415,4 @@ class DBObjectTest extends ItopDataTestCase
$this->assertEquals("2024-01-15 09:45:00", $oObject->Get('end_date'), 'SetComputedDate +2 weeks on a WorkOrder DateTimeAttribute');
}
public function testStringFitsInField()
{
//🎁 character is 4 bytes long
$sTooLongText = str_repeat('🎁', 17000);
$oLog = new EventRestService();
$this->assertFalse($oLog->StringFitsInField('json_output', $sTooLongText));
$sCorrectLengthText = str_repeat('🎁', 16383);
$this->assertTrue($oLog->StringFitsInField('json_output', $sCorrectLengthText));
$sCorrectLengthString = str_repeat('🎁', 255);
$this->assertTrue($oLog->StringFitsInField('operation', $sCorrectLengthString));
$sTooLongString = str_repeat('🎁', 256);
$this->assertFalse($oLog->StringFitsInField('operation', $sTooLongString));
}
}

View File

@@ -28,23 +28,23 @@ class RestServicesTest extends ItopDataTestCase
static::assertJsonStringEqualsJsonString($sExpectedJsonDataSanitized, $sOutputJson);
}
/**
* @return array[]
*/
public function providerTestSanitizeJsonInput(): array
{
return [
'core/check_credentials' => [
'{"operation": "core/check_credentials", "user": "admin", "password": "admin"}',
'{
/**
* @return array[]
*/
public function providerTestSanitizeJsonInput(): array
{
return [
'core/check_credentials' => [
'{"operation": "core/check_credentials", "user": "admin", "password": "admin"}',
'{
"operation": "core/check_credentials",
"user": "admin",
"password": "*****"
}'
],
'core/update' => [
'{"operation": "core/update", "comment": "Update user", "class": "UserLocal", "key": {"id":1}, "output_fields": "first_name, password", "fields": {"password" : "123456"}}',
'{
],
'core/update' => [
'{"operation": "core/update", "comment": "Update user", "class": "UserLocal", "key": {"id":1}, "output_fields": "first_name, password", "fields": {"password" : "123456"}}',
'{
"operation": "core/update",
"comment": "Update user",
"class": "UserLocal",
@@ -56,10 +56,10 @@ class RestServicesTest extends ItopDataTestCase
"password": "*****"
}
}'
],
'core/create' => [
'{"operation": "core/create", "comment": "Create user", "class": "UserLocal", "fields": {"first_name": "John", "last_name": "Doe", "email": "jd@example/com", "password" : "123456"}}',
'{
],
'core/create' => [
'{"operation": "core/create", "comment": "Create user", "class": "UserLocal", "fields": {"first_name": "John", "last_name": "Doe", "email": "jd@example/com", "password" : "123456"}}',
'{
"operation": "core/create",
"comment": "Create user",
"class": "UserLocal",
@@ -70,9 +70,9 @@ class RestServicesTest extends ItopDataTestCase
"password": "*****"
}
}'
],
];
}
],
];
}
/**
* @param $sOperation
@@ -93,33 +93,33 @@ class RestServicesTest extends ItopDataTestCase
static::assertJsonStringEqualsJsonString($sExpectedJsonDataSanitized, json_encode($oRestResultWithObject));
}
/**
* @return array[]
*/
public function providerTestSanitizeJsonOutput(): array
{
return [
/**
* @return array[]
*/
public function providerTestSanitizeJsonOutput(): array
{
return [
'core/update' => [
'core/update',
['comment' => 'Update user', 'class' => 'UserLocal', 'key' => ['login' => 'my_example'], 'output_fields' => 'password', 'fields' => ['password' => 'opkB!req57']],
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
],
'core/create' => [
'core/create',
['comment' => 'Create user', 'class' => 'UserLocal', 'fields' => ['password' => 'Azertyuiiop*12', 'login' => 'toto', 'profile_list' => [1]]],
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
],
'core/get' => [
'core/get',
['comment' => 'Get user', 'class' => 'UserLocal', 'key' => ['login' => 'my_example'], 'output_fields' => 'first_name, password'],
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
],
'core/check_credentials' => [
'core/check_credentials',
['user' => 'admin', 'password' => 'admin'],
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
],
];
}
'core/update' => [
'core/update',
['comment' => 'Update user', 'class' => 'UserLocal', 'key' => ['login' => 'my_example'], 'output_fields' => 'password', 'fields' => ['password' => 'opkB!req57']],
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
],
'core/create' => [
'core/create',
['comment' => 'Create user', 'class' => 'UserLocal', 'fields' => ['password' => 'Azertyuiiop*12', 'login' => 'toto', 'profile_list' => [1]]],
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
],
'core/get' => [
'core/get',
['comment' => 'Get user', 'class' => 'UserLocal', 'key' => ['login' => 'my_example'], 'output_fields' => 'first_name, password'],
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
],
'core/check_credentials' => [
'core/check_credentials',
['user' => 'admin', 'password' => 'admin'],
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
],
];
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Combodo\iTop\Test\UnitTest\Setup;
use Combodo\iTop\Test\UnitTest\ItopTestCase;
class ModuleDiscoveryTest extends ItopTestCase
{
public function GetModuleNameProvider()
{
return [
'nominal' => [
'sModuleId' => 'a/1.2.3',
'name' => 'a',
'version' => '1.2.3',
],
'develop' => [
'sModuleId' => 'a/1.2.3-dev',
'name' => 'a',
'version' => '1.2.3-dev',
],
'missing version => 1.0.0' => [
'sModuleId' => 'a/',
'name' => 'a',
'version' => '1.0.0',
],
'missing everything except name' => [
'sModuleId' => 'a',
'name' => 'a',
'version' => '1.0.0',
],
];
}
protected function setUp(): void
{
parent::setUp();
$this->RequireOnceItopFile('setup/modulediscovery.class.inc.php');
}
/**
* @dataProvider GetModuleNameProvider
*/
public function testGetModuleName($sModuleId, $expectedName, $expectedVersion)
{
$this->assertEquals([$expectedName, $expectedVersion], \ModuleDiscovery::GetModuleName($sModuleId));
}
}

View File

@@ -3,19 +3,21 @@
namespace Combodo\iTop\Test\UnitTest\SessionTracker;
use Combodo\iTop\Application\Helper\Session;
use Combodo\iTop\SessionTracker\iSessionHandlerExtension;
use Combodo\iTop\SessionTracker\SessionHandler;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use ContextTag;
class SessionHandlerTest extends ItopDataTestCase
{
private $aFiles ;
private $oTag ;
private $aFiles;
private $oTag;
protected function setUp(): void
{
parent::setUp();
$this->aFiles=[];
$this->RequireOnceUnitTestFile('./iSessionHandlerExtensionExamples.php');
$this->aFiles = [];
$this->oTag = new ContextTag(ContextTag::TAG_REST);
}
@@ -24,47 +26,53 @@ class SessionHandlerTest extends ItopDataTestCase
parent::tearDown();
$this->oTag = null;
foreach ($this->aFiles as $sFile){
if (is_file($sFile)){
foreach ($this->aFiles as $sFile) {
if (is_file($sFile)) {
@unlink($sFile);
}
}
}
private function CreateUserAndLogIn() : ? string {
private function CreateUserAndLogIn(): ?string
{
$_SESSION = [];
$oUser = $this->CreateContactlessUser("admin" . uniqid(), 1, "1234@Abcdefg");
$oUser = $this->CreateContactlessUser("admin".uniqid(), 1, "1234@Abcdefg");
\UserRights::Login($oUser->Get('login'));
return $oUser->GetKey();
}
private function GenerateSessionContent(SessionHandler $oSessionHandler, ?string $sPreviousFileVersionContent) : ?string {
private function GenerateSessionContent(SessionHandler $oSessionHandler, ?string $sPreviousFileVersionContent): ?string
{
return $this->InvokeNonPublicMethod(SessionHandler::class, "generate_session_content", $oSessionHandler, $aArgs = [$sPreviousFileVersionContent]);
}
/*
* @covers SessionHandler::generate_session_content
*/
public function testGenerateSessionContentNoUserLoggedIn(){
public function testGenerateSessionContentNoUserLoggedIn()
{
$oSessionHandler = new SessionHandler();
$sContent = $this->GenerateSessionContent($oSessionHandler, null);
$this->assertNull($sContent, "Session content should be null when there is no user logged in");
}
public function GenerateSessionContentCorruptedPreviousFileContentProvider() {
public function GenerateSessionContentCorruptedPreviousFileContentProvider()
{
return [
'not a json' => [ "not a json" ],
'not an array' => [ json_encode("not an array") ],
'array without creation_time key' => [ json_encode([]) ],
'not a json' => ["not a json"],
'not an array' => [json_encode("not an array")],
'array without creation_time key' => [json_encode([])],
];
}
/**
* @covers SessionHandler::generate_session_content
* @covers SessionHandler::generate_session_content
* @dataProvider GenerateSessionContentCorruptedPreviousFileContentProvider
*/
public function testGenerateSessionContent_SessionFileRepairment(?string $sFileContent){
public function testGenerateSessionContent_SessionFileRepairment(?string $sFileContent)
{
$sUserId = $this->CreateUserAndLogIn();
$oSessionHandler = new SessionHandler();
@@ -84,7 +92,8 @@ class SessionHandlerTest extends ItopDataTestCase
/*
* @covers SessionHandler::generate_session_content
*/
public function testGenerateSessionContent(){
public function testGenerateSessionContent()
{
$sUserId = $this->CreateUserAndLogIn();
$oSessionHandler = new SessionHandler();
@@ -105,33 +114,36 @@ class SessionHandlerTest extends ItopDataTestCase
// Switch context + change user id via impersonation
// check it is still tracked in session files
$oOtherUser = $this->CreateContactlessUser("admin" . uniqid(), 1, "1234@Abcdefg");
$oOtherUser = $this->CreateContactlessUser("admin".uniqid(), 1, "1234@Abcdefg");
$this->assertTrue(\UserRights::Impersonate($oOtherUser->Get('login')), "Failed to execute impersonate on: ".$oOtherUser->Get('login'));
$oTag2 = new ContextTag(ContextTag::TAG_SYNCHRO);
$sNewContent = $this->GenerateSessionContent($oSessionHandler, $sFirstContent);
$this->assertNotNull($sNewContent, 'Should not return null');
$aJson = json_decode($sNewContent, true);
$this->assertNotEquals(false, $aJson, 'Should return a valid json string, found: '.$sNewContent);
$this->assertEquals(ContextTag::TAG_REST . '|' . ContextTag::TAG_SYNCHRO, $aJson['context'] ?? '', "After impersonation, should report the new context tags in [context]: $sNewContent");
$this->assertEquals(ContextTag::TAG_REST.'|'.ContextTag::TAG_SYNCHRO, $aJson['context'] ?? '', "After impersonation, should report the new context tags in [context]: $sNewContent");
$this->assertEquals($iFirstSessionCreationTime, $aJson['creation_time'] ?? '', "After impersonation, should still report the the session start timestamp in [creation_time]: $sNewContent");
$this->assertEquals('foo_login_mode', $aJson['login_mode'] ?? '', "After impersonation, should still report the login mode in [login_mode]: $sNewContent");
$this->assertEquals($oOtherUser->GetKey(), $aJson['user_id'] ?? '', "Should report the impersonate user in [user_id]: $sNewContent");
}
private function touchSessionFile(SessionHandler $oSessionHandler, $session_id) : ?string {
private function touchSessionFile(SessionHandler $oSessionHandler, $session_id): ?string
{
$sRes = $this->InvokeNonPublicMethod(SessionHandler::class, "touch_session_file", $oSessionHandler, $aArgs = [$session_id]);
if (!is_null($sRes) && is_file($sRes)) {
// Record the file for cleanup on tearDown
$this->aFiles[] = $sRes;
}
clearstatcache();
return $sRes;
}
/*
* @covers SessionHandler::touch_session_file
*/
public function testTouchSessionFile_NoUserLoggedIn(){
public function testTouchSessionFile_NoUserLoggedIn()
{
$oSessionHandler = new SessionHandler();
$session_id = uniqid();
$sFile = $this->touchSessionFile($oSessionHandler, $session_id);
@@ -143,7 +155,8 @@ class SessionHandlerTest extends ItopDataTestCase
/*
* @covers SessionHandler::touch_session_file
*/
public function testTouchSessionFile_UserLoggedIn(){
public function testTouchSessionFile_UserLoggedIn()
{
$sUserId = $this->CreateUserAndLogIn();
Session::Set('login_mode', 'foo_login_mode');
@@ -174,7 +187,8 @@ class SessionHandlerTest extends ItopDataTestCase
/**
* @covers SessionHandler::touch_session_file
*/
public function testTouchSessionFileWithEmptySessionId() {
public function testTouchSessionFileWithEmptySessionId()
{
$this->CreateUserAndLogIn();
Session::Set('login_mode', 'toto');
@@ -183,32 +197,36 @@ class SessionHandlerTest extends ItopDataTestCase
$this->assertNull($this->touchSessionFile($oSessionHandler, false), 'Should return null when session id (boolean) false');
}
private function GetFilePath(SessionHandler $oSessionHandler, $session_id) : string {
private function GetFilePath(SessionHandler $oSessionHandler, $session_id): string
{
$sFile = $this->InvokeNonPublicMethod(SessionHandler::class, "get_file_path", $oSessionHandler, $aArgs = [$session_id]);
// Record file for cleanup on tearDown
$this->aFiles[] = $sFile;
return $sFile;
}
public function GgcWithTimeLimitProvider(){
public function GgcWithTimeLimitProvider()
{
return [
'no cleanup time limit' => [
'iTimeLimit' => -1,
'iExpectedProcessed' => 2
'no cleanup time limit' => [
'iTimeLimit' => -1,
'iExpectedProcessed' => 2,
],
'cleanup time limit in the pass => first file removed only' => [
'iTimeLimit' => time() - 1,
'iExpectedProcessed' => 1
'iTimeLimit' => time() - 1,
'iExpectedProcessed' => 1,
],
];
}
/**
* @covers SessionHandler::gc_with_time_limit
* @covers SessionHandler::list_session_files
* @covers SessionHandler::gc_with_time_limit
* @covers SessionHandler::list_session_files
* @dataProvider GgcWithTimeLimitProvider
*/
public function testGgcWithTimeLimit($iTimeLimit, $iExpectedProcessed) {
public function testGgcWithTimeLimit($iTimeLimit, $iExpectedProcessed)
{
$oSessionHandler = new SessionHandler();
//remove all first
$oSessionHandler->gc_with_time_limit(-1);
@@ -218,11 +236,11 @@ class SessionHandlerTest extends ItopDataTestCase
$iNbExpiredFiles = 2;
$iNbFiles = 5;
$iExpiredTimeStamp = time() - $max_lifetime - 1;
for($i=0; $i<$iNbFiles; $i++) {
for ($i = 0; $i < $iNbFiles; $i++) {
$sFile = $this->GetFilePath($oSessionHandler, uniqid());
file_put_contents($sFile, "fakedata");
if ($iNbExpiredFiles > 0){
if ($iNbExpiredFiles > 0) {
$iNbExpiredFiles--;
touch($sFile, $iExpiredTimeStamp);
}
@@ -230,7 +248,7 @@ class SessionHandlerTest extends ItopDataTestCase
$aFoundSessionFiles = $oSessionHandler->list_session_files();
$this->assertEquals($iNbFiles, sizeof($aFoundSessionFiles), 'list_session_files should reports all files');
foreach ($aFoundSessionFiles as $sFile){
foreach ($aFoundSessionFiles as $sFile) {
$this->assertTrue(is_file($sFile), 'list_session_files should return a valid file paths, found: '.$sFile);
}
@@ -238,4 +256,73 @@ class SessionHandlerTest extends ItopDataTestCase
$this->assertEquals($iExpectedProcessed, $iProcessed, 'gc_with_time_limit should report the count of expired files');
$this->assertEquals($iNbFiles - $iExpectedProcessed, sizeof($oSessionHandler->list_session_files()), 'gc_with_time_limit should actually remove all processed files');
}
}
public function testGetSessionHandlerExtension_NoExtension()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', '');
$oSessionHandler = new SessionHandler();
$oSessionHandlerExtension = $this->InvokeNonPublicMethod(SessionHandler::class, "GetSessionHandlerExtension", $oSessionHandler);
$this->assertNull($oSessionHandlerExtension, "by default no extension");
}
public function testGetSessionHandlerExtension_InvalidClassExtension()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', 'dddf');
$oSessionHandler = new SessionHandler();
$oSessionHandlerExtension = $this->InvokeNonPublicMethod(SessionHandler::class, "GetSessionHandlerExtension", $oSessionHandler);
$this->assertNull($oSessionHandlerExtension);
}
public function testGetSessionHandlerExtension_InvalidExtension()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', Session::class);
$oSessionHandler = new SessionHandler();
$oSessionHandlerExtension = $this->InvokeNonPublicMethod(SessionHandler::class, "GetSessionHandlerExtension", $oSessionHandler);
$this->assertNull($oSessionHandlerExtension);
}
public function testGetSessionHandlerExtension_OK()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', 'Combodo\iTop\Test\UnitTest\SessionTracker\BasicSessionHandlerExtension');
$oSessionHandler = new SessionHandler();
$oSessionHandlerExtension = $this->InvokeNonPublicMethod(SessionHandler::class, "GetSessionHandlerExtension", $oSessionHandler);
$this->assertNotNull($oSessionHandlerExtension, "by default no extension");
$this->assertTrue($oSessionHandlerExtension instanceof iSessionHandlerExtension);
$this->assertInstanceOf(BasicSessionHandlerExtension::class, $oSessionHandlerExtension);
}
public function testGenerateSessionContent_WithAdditionalDataProvidedBySessionHandlerExtension()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', 'Combodo\iTop\Test\UnitTest\SessionTracker\BasicSessionHandlerExtension');
$sUserId = $this->CreateUserAndLogIn();
$oSessionHandler = new SessionHandler();
Session::Set('login_mode', 'foo_login_mode');
//first time
$sFirstContent = $this->GenerateSessionContent($oSessionHandler, null);
$this->assertNotNull($sFirstContent, 'Should not return null');
$aJson = json_decode($sFirstContent, true);
$this->assertNotEquals(false, $aJson, 'Should return a valid json string, found: '.$sFirstContent);
$this->assertEquals($sUserId, $aJson['user_id'] ?? '', "Should report the login of the logged in user in [user_id]: $sFirstContent");
$this->assertEquals(ContextTag::TAG_REST, $aJson['context'] ?? '', "Should report the context tag(s) in [context]: $sFirstContent");
$this->assertIsInt($aJson['creation_time'] ?? '', "Should report the session start timestamp in [creation_time]: $sFirstContent");
$this->assertEquals('foo_login_mode', $aJson['login_mode'] ?? '', "Should report the current login mode in [login_mode]: $sFirstContent");
$this->assertEquals('gabuzomeu', $aJson['shadok'] ?? '', "Should report the current login mode in [shadok]: $sFirstContent");
}
public function testGenerateSessionContentWithPreviousNonArrayContentAndWithAdditionalDataProvidedBySessionHandlerExtension()
{
\utils::GetConfig()->Set('sessions_tracking.session_handler_extension', 'Combodo\iTop\Test\UnitTest\SessionTracker\BasicSessionHandlerExtension');
$this->CreateUserAndLogIn();
$oSessionHandler = new SessionHandler();
$sContent = $this->GenerateSessionContent($oSessionHandler, json_encode(null));
$this->assertNotNull($sContent, "Call to CompleteSessionData should NOT fail due to Argument #1 (\$aJson) must be of type array, null given");
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Combodo\iTop\Test\UnitTest\SessionTracker;
use Combodo\iTop\SessionTracker\iSessionHandlerExtension;
class BasicSessionHandlerExtension implements iSessionHandlerExtension {
public function __construct(){
}
public function CompleteSessionData(array $aJson, array &$aData): void
{
$aData['shadok']='gabuzomeu';
}
}

View File

@@ -227,7 +227,7 @@ try
/** @var iRestServiceProvider $oRS */
$oRS = $aOpToRestService[$sOperation]['service_provider'];
$sProvider = get_class($oRS);
if ($oRS instanceof iRestInputSanitizer) {
$sSanitizedJsonInput = $oRS->SanitizeJsonInput($sJsonString);
}
@@ -299,12 +299,7 @@ if (MetaModel::GetConfig()->Get('log_rest_service'))
$oLog->SetTrim('message', $sMessage);
$oLog->Set('code', $oResult->code);
$oResult->SanitizeContent();
$iUnescapeSlashAndUnicode = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
$sJsonOuputWithPrettyPrinting = json_encode($oResult, $iUnescapeSlashAndUnicode | JSON_PRETTY_PRINT);
$sJsonOutputWithoutPrettyPrinting = json_encode($oResult, $iUnescapeSlashAndUnicode);
!$oLog->StringFitsInField('json_output', $sJsonOuputWithPrettyPrinting) ?
$oLog->SetTrim('json_output', $sJsonOutputWithoutPrettyPrinting) : // too long, we don't make it pretty
$oLog->SetTrim('json_output', $sJsonOuputWithPrettyPrinting);
$oLog->SetTrim('json_output', json_encode($oResult, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
$oLog->DBInsertNoReload();
}