Compare commits

..

56 Commits

Author SHA1 Message Date
Eric Espie
3c80c93b4f Dashlet extraction 2026-01-16 18:47:28 +01:00
Eric Espie
efc6e6730b Dashlet extraction 2026-01-16 09:57:14 +01:00
Eric Espie
3769bc1024 Dashlet definition for core dashlets 2026-01-16 09:34:07 +01:00
Stephen Abello
e5338f28eb Save actions submit the form, it has yet to validate the form 2026-01-15 15:45:52 +01:00
Stephen Abello
5cfe7fa6eb Allow dashboard to restore state (either saved state or from backend). Restore old state on edition cancel 2026-01-15 11:51:49 +01:00
Stephen Abello
27c16a782c Remove done todo 2026-01-15 11:09:44 +01:00
Stephen Abello
7c21178e1d Handle backend save response in dashboard js 2026-01-15 11:08:20 +01:00
Stephen Abello
3a6e148c11 Prepare steps for custom dashboard handling 2026-01-15 10:56:35 +01:00
Eric Espie
4d9e18890a fix warnings 2026-01-15 10:44:20 +01:00
Eric Espie
50ffaa2b55 Read custom dashboards with grid format 2026-01-15 10:19:33 +01:00
Eric Espie
15c8f5903b save dashboard controller 2026-01-14 16:57:19 +01:00
Stephen Abello
0bc6f5d56a Align posted dashboard data to new data denormalized format 2026-01-14 11:39:56 +01:00
Stephen Abello
d248524cc8 Align posted dashboard data to new data denormalized format 2026-01-14 11:15:15 +01:00
Stephen Abello
410dc152d7 Make cloning dashlet actually use original dashlet data to get a new similar dashlet 2026-01-14 10:01:38 +01:00
Stephen Abello
423413e3a0 Fix form interaction with buttons when screen is smaller 2026-01-14 09:42:37 +01:00
Stephen Abello
8896c576d7 Make form style + button style match mockup 2026-01-14 09:32:11 +01:00
Benjamin DALSASS
975046da17 Add ChoiceImageFormBlock 2026-01-14 08:19:03 +01:00
Benjamin DALSASS
e4a281c3ff Add ChoiceImageFormBlock 2026-01-14 07:32:29 +01:00
Eric Espie
90729f84b6 Polymorphic type 2026-01-13 18:00:34 +01:00
Stephen Abello
c075a5c145 Make dashlet edition / refresh better interact with listener and gridstack library in order to allow multiple edits without breaking 2026-01-13 16:30:00 +01:00
Benjamin DALSASS
cd6d130bcb Move dashboard blocks to itop project and keep demonstrator one 2026-01-13 11:24:56 +01:00
Stephen Abello
7ca2c56dad Send denormalized data to backend in order to persist dashboard 2026-01-13 11:18:18 +01:00
Benjamin DALSASS
dd0ac58643 Prepare property service for form block dashboard 2026-01-13 07:36:47 +01:00
Stephen Abello
df943ec8b5 Change DashletBadge preferred height 2026-01-12 16:28:18 +01:00
Stephen Abello
076a6d0495 Make dashlet position non-random. Use their preferred width/height for now 2026-01-12 16:26:52 +01:00
Stephen Abello
02e59c906b Remove dummy buttons used for development purpose 2026-01-12 16:11:43 +01:00
Stephen Abello
49f91961e7 Make dashlet rendering computing request data 2026-01-12 15:09:14 +01:00
Stephen Abello
441519d71d Rename parameter 2026-01-12 15:08:33 +01:00
Eric Espie
5c75d0ce7c Fix some value types 2026-01-12 13:50:28 +01:00
Eric Espie
2efe80265d Pass form values from dashlet 2026-01-12 12:02:45 +01:00
Eric Espie
b58a64e143 Add Icon selection formBlock 2026-01-12 11:44:44 +01:00
Stephen Abello
ff11aec7fe Make clone dashlet ask for a rendered dashlet to the backend 2026-01-12 11:10:08 +01:00
Benjamin DALSASS
f79bb9d51c Add option display to form (css needs updates)
Add options with_run_button and with_book_button to FormBlockOql
2026-01-12 08:00:17 +01:00
Stephen Abello
3c365fc103 Make add / edit in dashboard interactive, and pass on data 2026-01-09 16:31:36 +01:00
Stephen Abello
7b193dd737 Use npm for gridstack, remove unnecessary folders using our dedicated service 2026-01-09 15:10:10 +01:00
Eric Espie
1538596db8 PHP CS-Fixer 2026-01-09 11:04:38 +01:00
Eric Espie
9d4fc345bc Fix (de)normalized data for Forms 2026-01-09 10:51:32 +01:00
Eric Espie
08c9309572 Fix (de)normalized data for Forms 2026-01-08 17:41:58 +01:00
Eric Espie
d072aa05f1 Prepare (de)normalized data for Forms 2026-01-08 17:28:48 +01:00
Eric Espie
85c1f091e2 Prepare normalized data for Forms 2026-01-08 17:25:52 +01:00
Eric Espie
be6a8abdf4 N°9066 - Split XML serializer into normalizer and encoder 2026-01-08 17:23:06 +01:00
Benjamin DALSASS
60bcf0c85f Change AbstractForm BindingReceivedEvent 2026-01-08 16:02:23 +01:00
Benjamin DALSASS
4a8804b8ac Dashlet form in new dashboard layout (suite) 2026-01-08 15:30:51 +01:00
Benjamin DALSASS
b014b9f638 Dashlet form in new dashboard layout 2026-01-08 14:42:16 +01:00
Eric Espie
1c633c6173 typo 2026-01-08 13:45:11 +01:00
Stephen Abello
cdc95aca7b Dump autoloader 2026-01-08 10:18:30 +01:00
Stephen Abello
b4460999ef Dump autoloader 2026-01-08 10:17:35 +01:00
Stephen Abello
a713e1b56e N°8641 - Dashboard editor front-end first commit for Form SDK integration.
* No dashlet edition
* Dashboard are not persisted
* Unable to load a dashboard from an endpoint (refresh)
* Grid library need proper npm integration
2026-01-08 10:17:30 +01:00
Vincent Dumas
3e879c64a7 N°4032 - On UserRequest, change proposed service subcategories (#786)
* N°4032 - On UserRequest, service subcategory no more limited by request_type
2026-01-08 10:08:52 +01:00
Eric Espie
5c6369b9b8 N°9065 - XML Definition for Dashlet properties 2026-01-07 17:16:50 +01:00
Eric Espie
154fb5c737 N°9066 - Serialization/Unserialization from XML to Forms 2026-01-07 17:09:47 +01:00
Eric Espie
efb1bd765b N°9065 - XML Definition for Dashlet properties 2026-01-07 17:09:20 +01:00
Eric Espie
b39af74d07 Fix CI 2026-01-07 09:04:56 +01:00
Eric Espie
904cd0b518 N°8772 - Move DIService into PSR-11 Service Locator 2025-12-30 14:27:28 +01:00
Benjamin Dalsass
4c1ad0f4f2 N°8772 - Form dependencies manager implementation
- Form SDK implementation
- Basic Forms
- Dynamics Forms
- Basic Blocks + Data Model Block
- Form Compilation
- Turbo integration
2025-12-30 11:42:55 +01:00
v-dumas
3955b4eb22 N°8534 - Prevent ending on Portal 2025-12-22 17:49:47 +01:00
1093 changed files with 144816 additions and 28018 deletions

16
.phpstorm.meta.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace PHPSTORM_META
{
override(\MetaModel::NewObject(0), map([
'' => '@',
]));
override(\MetaModel::GetObject(0), map([
'' => '@',
]));
}

View File

@@ -16,5 +16,5 @@ require_once(APPROOT.'/application/audit.category.class.inc.php');
require_once(APPROOT.'/application/audit.domain.class.inc.php');
require_once(APPROOT.'/application/audit.rule.class.inc.php');
require_once(APPROOT.'/application/query.class.inc.php');
require_once(APPROOT.'/setup/moduleinstallation/moduleinstallation.class.inc.php');
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');

View File

@@ -5,6 +5,9 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\Dashboard\Layout\DashboardLayoutGrid;
use Combodo\iTop\Application\Dashlet\DashletFactory;
use Combodo\iTop\Application\Dashlet\Service\DashletService;
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu;
@@ -12,9 +15,12 @@ use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\DesignDocument;
use Combodo\iTop\DesignElement;
use Combodo\iTop\PropertyType\PropertyTypeDesign;
use Combodo\iTop\Service\DependencyInjection\ServiceLocator;
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
require_once(APPROOT.'core/modelreflection.class.inc.php');
/**
@@ -24,7 +30,7 @@ require_once(APPROOT.'core/modelreflection.class.inc.php');
*/
abstract class Dashboard
{
/** @var string $sTitle*/
/** @var string $sTitle */
protected $sTitle;
/** @var bool $bAutoReload */
protected $bAutoReload;
@@ -34,7 +40,7 @@ abstract class Dashboard
protected $sLayoutClass;
/** @var array $aWidgetsData */
protected $aWidgetsData;
/** @var \DOMNode|null $oDOMNode */
/** @var DesignElement|null $oDOMNode */
protected $oDOMNode;
/** @var string $sId */
protected $sId;
@@ -43,6 +49,11 @@ abstract class Dashboard
/** @var \ModelReflection $oMetaModel */
protected $oMetaModel;
/** @var array Array of dashlets with position */
protected array $aGridDashlets = [];
protected $oDashletFactory;
/**
* Dashboard constructor.
*
@@ -57,6 +68,7 @@ abstract class Dashboard
$this->aCells = [];
$this->oDOMNode = null;
$this->sId = $sId;
$this->oDashletFactory = DashletFactory::GetInstance();
}
/**
@@ -68,7 +80,7 @@ abstract class Dashboard
{
$this->aCells = []; // reset the content of the dashboard
set_error_handler(['Dashboard', 'ErrorHandler']);
$oDoc = new DOMDocument();
$oDoc = new PropertyTypeDesign();
$oDoc->loadXML($sXml);
restore_error_handler();
$this->FromDOMDocument($oDoc);
@@ -77,10 +89,15 @@ abstract class Dashboard
/**
* @param \DOMDocument $oDoc
*/
public function FromDOMDocument(DOMDocument $oDoc)
public function FromDOMDocument(DesignDocument $oDoc)
{
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
if ($this->oDOMNode->getElementsByTagName('cells')->count() === 0) {
$this->FromDOMDocumentV2($oDoc);
return;
}
if ($oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0)) {
$this->sLayoutClass = $oLayoutNode->textContent;
} else {
@@ -121,7 +138,7 @@ abstract class Dashboard
$aDashletOrder = [];
/** @var \DOMElement $oDomNode */
foreach ($oDashletList as $oDomNode) {
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
if ($oRank) {
$iRank = (float)$oRank->textContent;
}
@@ -147,7 +164,39 @@ abstract class Dashboard
}
/**
* @param \DOMElement $oDomNode
* @param \DOMDocument $oDoc
*/
public function FromDOMDocumentV2(DesignDocument $oDoc)
{
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
$this->sLayoutClass = DashboardLayoutGrid::class;
$this->sTitle = $this->oDOMNode->GetChildText('title', '');
$iRefresh = intval($this->oDOMNode->GetChildText('refresh', '0'));
$this->bAutoReload = $iRefresh > 0;
$this->iAutoReloadSec = $iRefresh;
$oDashletsNode = $this->oDOMNode->GetUniqueElement('pos_dashlets');
$oDashletList = $oDashletsNode->getElementsByTagName('pos_dashlet');
foreach ($oDashletList as $oPosDashletNode) {
$aGridDashlet = [];
$aGridDashlet['position_x'] = intval($oPosDashletNode->GetChildText('position_x', '0'));
$aGridDashlet['position_y'] = intval($oPosDashletNode->GetChildText('position_y', '0'));
$aGridDashlet['width'] = intval($oPosDashletNode->GetChildText('width', '2'));
$aGridDashlet['height'] = intval($oPosDashletNode->GetChildText('height', '1'));
$oDashletNode = $oPosDashletNode->GetUniqueElement('dashlet');
$sId = $oPosDashletNode->getAttribute('id');
$oDashlet = $this->InitDashletFromDOMNode($oDashletNode);
$oDashlet->SetID($sId);
$aGridDashlet['dashlet'] = $oDashlet;
$this->aGridDashlets[] = $aGridDashlet;
}
}
/**
* @param DesignElement $oDomNode
*
* @return mixed
*/
@@ -160,7 +209,7 @@ abstract class Dashboard
// Test if dashlet can be instantiated, otherwise (uninstalled, broken, ...) we display a placeholder
$sClass = static::GetDashletClassFromType($sDashletType);
/** @var \Dashlet $oNewDashlet */
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
$oNewDashlet = $this->oDashletFactory->CreateDashlet($sClass, $sId);
$oNewDashlet->SetDashletType($sDashletType);
$oNewDashlet->FromDOMNode($oDomNode);
@@ -204,20 +253,33 @@ abstract class Dashboard
*/
public function ToXml()
{
$oDoc = new DOMDocument();
$oDoc->formatOutput = true; // indent (must be loaded with option LIBXML_NOBLANKS)
$oDoc->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
$oMainNode = $oDoc->createElement('dashboard');
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
$oDoc->appendChild($oMainNode);
$oMainNode = $this->CreateEmptyDashboard();
$this->ToDOMNode($oMainNode);
$sXml = $oDoc->saveXML();
$sXml = $oMainNode->ownerDocument->saveXML();
return $sXml;
}
/**
* @return DesignElement
* @throws \DOMException
*/
public function CreateEmptyDashboard(): DesignElement
{
$oDoc = new DesignDocument();
$oDoc->formatOutput = true; // indent (must be loaded with option LIBXML_NOBLANKS)
$oDoc->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
/** @var DesignElement $oMainNode */
$oMainNode = $oDoc->createElement('dashboard');
$oMainNode->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$oDoc->appendChild($oMainNode);
return $oMainNode;
}
/**
* @param \DOMElement $oDefinition
*/
@@ -279,7 +341,7 @@ abstract class Dashboard
}
$this->sTitle = $aParams['title'];
$this->bAutoReload = $aParams['auto_reload'] == 'true';
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int) $aParams['auto_reload_sec']);
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$aParams['auto_reload_sec']);
foreach ($aParams['cells'] as $aCell) {
$aCellDashlets = [];
@@ -287,7 +349,7 @@ abstract class Dashboard
$sDashletClass = $aDashletParams['dashlet_class'];
$sId = $aDashletParams['dashlet_id'];
/** @var \Dashlet $oNewDashlet */
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
$oNewDashlet = $this->oDashletFactory->CreateDashlet($sDashletClass, $sId);
if (isset($aDashletParams['dashlet_type'])) {
$oNewDashlet->SetDashletType($aDashletParams['dashlet_type']);
}
@@ -305,7 +367,11 @@ abstract class Dashboard
public function Save()
{
}
public function PersistDashboard(string $sXml): bool
{
return true;
}
/**
@@ -503,7 +569,7 @@ EOF
{
$aExtraParams['dashboard_div_id'] = utils::Sanitize($aExtraParams['dashboard_div_id'] ?? null, $this->GetId(), utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
/** @var \DashboardLayoutMultiCol $oLayout */
/** @var \DashboardLayout $oLayout */
$oLayout = new $this->sLayoutClass();
foreach ($this->aCells as $iCellIdx => $aDashlets) {
@@ -513,7 +579,13 @@ EOF
}
}
$oDashboard = $oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (count($this->aCells) > 0) {
$aDashlets = $this->aCells;
} else {
$aDashlets = $this->aGridDashlets;
}
$oDashboard = $oLayout->Render($oPage, $aDashlets, $bEditMode, $aExtraParams);
$oPage->AddUiBlock($oDashboard);
$bFromDasboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;
@@ -603,29 +675,12 @@ JS
* Return an array of dashlets available for selection.
*
* @return array
* @throws \ReflectionException
* @throws \Combodo\iTop\Application\Dashlet\DashletException
* @throws \DOMFormatException
*/
protected function GetAvailableDashlets()
protected function GetAvailableDashlets(): array
{
$aDashlets = [];
foreach (get_declared_classes() as $sDashletClass) {
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instantiated.
if (is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, ['DashletUnknown', 'DashletProxy'])) {
$oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract()) {
$aCallSpec = [$sDashletClass, 'IsVisible'];
$bVisible = call_user_func($aCallSpec);
if ($bVisible) {
$aCallSpec = [$sDashletClass, 'GetInfo'];
$aInfo = call_user_func($aCallSpec);
$aDashlets[$sDashletClass] = $aInfo;
}
}
}
}
return $aDashlets;
return DashletService::GetInstance()->GetAvailableDashlets();
}
/**
@@ -640,6 +695,7 @@ JS
$iNewId = max($iNewId, (int)$oDashlet->GetID());
}
}
return $iNewId + 1;
}
@@ -674,6 +730,7 @@ JS
if (is_subclass_of($sType, 'Dashlet')) {
return $sType;
}
return 'DashletUnknown';
}
@@ -726,6 +783,8 @@ class RuntimeDashboard extends Dashboard
{
parent::__construct($sId);
$this->oMetaModel = new ModelReflectionRuntime();
$this->oDashletFactory->SetModelReflectionRuntime($this->oMetaModel);
ServiceLocator::GetInstance()->RegisterService('ModelReflection', $this->oMetaModel);
$this->bCustomized = false;
}
@@ -740,6 +799,7 @@ class RuntimeDashboard extends Dashboard
/**
* @param bool $bCustomized
*
* @since 2.7.0
*/
public function SetCustomFlag($bCustomized)
@@ -764,6 +824,26 @@ class RuntimeDashboard extends Dashboard
public function Save()
{
$sXml = $this->ToXml();
return $this->PersistDashboard($sXml);
}
/**
* @param string $sXml
*
* @return bool
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public function PersistDashboard(string $sXml): bool
{
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
@@ -784,6 +864,7 @@ class RuntimeDashboard extends Dashboard
utils::PushArchiveMode(false);
$oUserDashboard->DBWrite();
utils::PopArchiveMode();
return $bIsNew;
}
@@ -1077,6 +1158,7 @@ JS
$sId = utils::Sanitize($this->GetId(), '', 'element_identifier');
$sMenuTogglerId = "ibo-dashboard-menu-toggler-{$sId}";
$sActionEditId = "ibo-dashboard-menu-edit-{$sId}";
$sPopoverMenuId = "ibo-dashboard-menu-popover-{$sId}";
$sName = 'UI:Dashboard:Actions';
@@ -1090,6 +1172,21 @@ JS
} else {
$oToolbar = $oDashboard->GetToolbar();
}
// TODO 3.3 Check if we need different action for custom dashboard creation / edition
$oActionEditButton = ButtonUIBlockFactory::MakeIconAction(
'fas fa-pen',
$this->HasCustomDashboard() ? Dict::S('UI:Dashboard:EditCustom') : Dict::S('UI:Dashboard:CreateCustom'),
$sActionEditId,
'',
false,
$sActionEditId
)
->AddCSSClass('ibo-top-bar--toolbar-dashboard-edit-button')
->AddCSSClass('ibo-action-button');
$oToolbar->AddSubBlock($oActionEditButton);
$oActionButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', Dict::S($sName), $sName, '', false, $sMenuTogglerId)
->AddCSSClass('ibo-top-bar--toolbar-dashboard-menu-toggler')
->AddCSSClass('ibo-action-button');
@@ -1099,8 +1196,8 @@ JS
$sFile = addslashes(utils::LocalPath($this->sDefinitionFile));
$sJSExtraParams = json_encode($aExtraParams);
if ($this->HasCustomDashboard()) {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
// $oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
// $aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
$oRevert = new JSPopupMenuItem(
'UI:Dashboard:RevertConfirm',
Dict::S('UI:Dashboard:DeleteCustom'),
@@ -1108,8 +1205,8 @@ JS
);
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
} else {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
// $oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
// $aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
}
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
@@ -1223,7 +1320,7 @@ EOF
$sId = json_encode($this->sId);
$sLayoutClass = json_encode($this->sLayoutClass);
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
$sAutoReloadSec = (string) $this->iAutoReloadSec;
$sAutoReloadSec = (string)$this->iAutoReloadSec;
$sTitle = json_encode($this->sTitle);
$sFile = json_encode($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
@@ -1395,19 +1492,11 @@ JS
// Get the list of possible dashlets that support a creation from
// an OQL
$aAllDashlets = DashletService::GetInstance()->GetAvailableDashlets();
$aDashlets = [];
foreach (get_declared_classes() as $sDashletClass) {
if (is_subclass_of($sDashletClass, 'Dashlet')) {
$oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract()) {
$aCallSpec = [$sDashletClass, 'CanCreateFromOQL'];
$bShorcutMode = call_user_func($aCallSpec);
if ($bShorcutMode) {
$aCallSpec = [$sDashletClass, 'GetInfo'];
$aInfo = call_user_func($aCallSpec);
$aDashlets[$sDashletClass] = ['label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']];
}
}
foreach ($aAllDashlets as $sDashletClass => $aInfo) {
if ($aInfo['can_create_by_oql']) {
$aDashlets[$sDashletClass] = ['label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']];
}
}
@@ -1417,7 +1506,7 @@ JS
$oSubForm = new DesignerForm();
$oMetaModel = new ModelReflectionRuntime();
/** @var \Dashlet $oDashlet */
$oDashlet = new $sDashletClass($oMetaModel, 0);
$oDashlet = DashletFactory::GetInstance()->CreateDashlet($sDashletClass, 0);
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
@@ -1571,7 +1660,7 @@ JS
*/
private function UpdateDashletUserPrefs(Dashlet $oDashlet, $sDashletIdOrig, array $aExtraParams)
{
$bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList);
$bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList);
if (!$bIsDashletWithListPref) {
return;
}
@@ -1619,6 +1708,7 @@ JS
//on error, return default value
return null;
}
return DataTableSettings::GetAppUserPreferenceKey($aClassAliases, $sDataTableId);
}
}

View File

@@ -30,7 +30,7 @@ use Combodo\iTop\Application\WebPage\WebPage;
*/
abstract class DashboardLayout
{
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
abstract public function Render($oPage, $aDashlets, $bEditMode = false, array $aExtraParams = []);
/**
* @param int $iCellIdx
@@ -43,8 +43,8 @@ abstract class DashboardLayout
public static function GetInfo()
{
return [
'label' => '',
'icon' => '',
'label' => '',
'icon' => '',
'description' => '',
];
}
@@ -74,6 +74,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
}
$idx++;
}
return $aDashlets;
}
@@ -94,6 +95,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
}
$idx++;
}
return $aCells;
}
@@ -109,7 +111,8 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
// Trim the list of cells to remove the invisible/empty ones at the end of the array
$aCells = $this->TrimCellsArray($aCells);
$oDashboardLayout = new DashboardLayoutUIBlock();
// TODO 3.3 Handle dashboard new format, convert old format if needed
$oDashboardLayout = new DashboardLayoutUIBlock($aExtraParams['dashboard_div_id']);
//$oPage->AddUiBlock($oDashboardLayout);
$iCellIdx = 0;
@@ -117,15 +120,16 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
//Js given by each dashlet to reload
$sJSReload = "";
$oDashboardGrid = new \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardGrid();
$oDashboardLayout->SetGrid($oDashboardGrid);
for ($iRows = 0; $iRows < $iNbRows; $iRows++) {
$oDashboardRow = new DashboardRow();
$oDashboardLayout->AddDashboardRow($oDashboardRow);
//$oDashboardLayout->AddDashboardRow($oDashboardRow);
for ($iCols = 0; $iCols < $this->iNbCols; $iCols++) {
$oDashboardColumn = new DashboardColumn($bEditMode);
$oDashboardColumn->SetCellIndex($iCellIdx);
$oDashboardRow->AddDashboardColumn($oDashboardColumn);
//$oDashboardRow->AddDashboardColumn($oDashboardColumn);
if (array_key_exists($iCellIdx, $aCells)) {
$aDashlets = $aCells[$iCellIdx];
@@ -133,6 +137,18 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
/** @var \Dashlet $oDashlet */
foreach ($aDashlets as $oDashlet) {
if ($oDashlet::IsVisible()) {
$sDashletId = $oDashlet->GetID();
$sDashletClass = get_class($oDashlet);
$aDashletDenormalizedProperties = $oDashlet->GetDenormalizedProperties();
// $aDashletsInfo = $sDashletClass::GetInfo();
//
// // TODO 3.3 Gather real position and height/width if any.
// // Also set minimal height/width
// $iPositionX = null;
// $iPositionY = null;
// $iWidth = array_key_exists('preferred_width', $aDashletsInfo) ? $aDashletsInfo['preferred_width'] : 1;
// $iHeight = array_key_exists('preferred_height', $aDashletsInfo) ? $aDashletsInfo['preferred_height'] : 1;
// $oDashboardGrid->AddDashlet($oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams), $sDashletId, $sDashletClass, $aDashletDenormalizedProperties, $iPositionX, $iPositionY, $iWidth, $iHeight);
$oDashboardColumn->AddUIBlock($oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams));
}
}
@@ -147,6 +163,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$sJSReload .= $oDashboardRow->GetJSRefreshCallback()." ";
}
// TODO 3.3 We can probably do better with the new dashboard
$oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}");
if ($bEditMode) { // Add one row for extensibility
@@ -168,8 +185,8 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
*/
public function GetDashletCoordinates($iCellIdx)
{
$iColNumber = (int) $iCellIdx % $this->iNbCols;
$iRowNumber = (int) floor($iCellIdx / $this->iNbCols);
$iColNumber = (int)$iCellIdx % $this->iNbCols;
$iRowNumber = (int)floor($iCellIdx / $this->iNbCols);
return [$iColNumber, $iRowNumber];
}
@@ -182,11 +199,12 @@ class DashboardLayoutOneCol extends DashboardLayoutMultiCol
parent::__construct();
$this->iNbCols = 1;
}
public static function GetInfo()
{
return [
'label' => 'One Column',
'icon' => 'images/layout_1col.png',
'label' => 'One Column',
'icon' => 'images/layout_1col.png',
'description' => '',
];
}
@@ -199,11 +217,12 @@ class DashboardLayoutTwoCols extends DashboardLayoutMultiCol
parent::__construct();
$this->iNbCols = 2;
}
public static function GetInfo()
{
return [
'label' => 'Two Columns',
'icon' => 'images/layout_2col.png',
'label' => 'Two Columns',
'icon' => 'images/layout_2col.png',
'description' => '',
];
}
@@ -216,11 +235,12 @@ class DashboardLayoutThreeCols extends DashboardLayoutMultiCol
parent::__construct();
$this->iNbCols = 3;
}
public static function GetInfo()
{
return [
'label' => 'Two Columns',
'icon' => 'images/layout_3col.png',
'label' => 'Two Columns',
'icon' => 'images/layout_3col.png',
'description' => '',
];
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://www.combodo.com/itop-schema/3.3"
version="3.3">
<classes>
<class id="AbstractResource" _delta="define">
<parent>cmdbAbstractObject</parent>
<properties>
<comment>/* Resource access control abstraction. Can be herited by abstract resource access control classes. Generaly controlled using UR_ACTION_MODIFY access right. */</comment>
<comment>/* Resource access control abstraction. Can be inherited by abstract resource access control classes. Generally controlled using UR_ACTION_MODIFY access right. */</comment>
<abstract>true</abstract>
</properties>
<presentation/>
@@ -552,7 +554,7 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
<description><![CDATA[Inform the listeners about the connection states]]></description>
<event_data>
<event_datum id="code">
<description>The login step result code (LoginWebPage::EXIT_CODE_...) </description>
<description>The login step result code (LoginWebPage::EXIT_CODE_...)</description>
<type>integer</type>
</event_datum>
<event_datum id="state">
@@ -849,5 +851,454 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
</methods>
</class>
</classes>
<dashlets>
<dashlet id="DashletGroupByTable" _delta="define">
<label>UI:DashletGroupByTable:Label</label>
<icon>images/dashlets/icons8-transaction-list-48.png</icon>
<description>UI:DashletGroupByTable:Description</description>
<min_width>2</min_width>
<min_height>2</min_height>
<preferred_width>3</preferred_width>
<preferred_height>3</preferred_height>
<can_create_by_oql>true</can_create_by_oql>
<configuration/>
</dashlet>
<dashlet id="DashletGroupByBars" _delta="define">
<label>UI:DashletGroupByBars:Label</label>
<icon>images/dashlets/icons8-bar-chart-48.png</icon>
<description>UI:DashletGroupByBars:Description</description>
<min_width>2</min_width>
<min_height>2</min_height>
<preferred_width>3</preferred_width>
<preferred_height>3</preferred_height>
<can_create_by_oql>true</can_create_by_oql>
<configuration/>
</dashlet>
<dashlet id="DashletGroupByPie" _delta="define">
<label>UI:DashletGroupByPie:Label</label>
<icon>images/dashlets/icons8-pie-chart-48.png</icon>
<description>UI:DashletGroupByPie:Description</description>
<min_width>2</min_width>
<min_height>2</min_height>
<preferred_width>3</preferred_width>
<preferred_height>3</preferred_height>
<can_create_by_oql>true</can_create_by_oql>
<configuration/>
</dashlet>
<dashlet id="DashletBadge" _delta="define">
<label>UI:DashletBadge:Label</label>
<icon>images/dashlets/icons8-badge-48.png</icon>
<description>UI:DashletBadge:Description</description>
<min_width>2</min_width>
<min_height>1</min_height>
<preferred_width>2</preferred_width>
<preferred_height>1</preferred_height>
<configuration/>
</dashlet>
<dashlet id="DashletHeaderDynamic" _delta="define">
<label>UI:DashletHeaderDynamic:Label</label>
<icon>images/dashlets/icons8-header-altered-48.png</icon>
<description>UI:DashletHeaderDynamic:Description</description>
<min_width>2</min_width>
<min_height>1</min_height>
<preferred_width>4</preferred_width>
<preferred_height>3</preferred_height>
<configuration/>
</dashlet>
<dashlet id="DashletHeaderStatic" _delta="define">
<label>UI:DashletHeaderStatic:Label</label>
<icon>images/dashlets/icons8-header-48.png</icon>
<description>UI:DashletHeaderStatic:Description</description>
<min_width>4</min_width>
<min_height>1</min_height>
<preferred_width>4</preferred_width>
<preferred_height>1</preferred_height>
<configuration/>
</dashlet>
<dashlet id="DashletObjectList" _delta="define">
<label>UI:DashletObjectList:Label</label>
<icon>images/dashlets/icons8-list-48.png</icon>
<description>UI:DashletObjectList:Description</description>
<min_width>2</min_width>
<min_height>1</min_height>
<preferred_width>4</preferred_width>
<preferred_height>3</preferred_height>
<can_create_by_oql>true</can_create_by_oql>
<configuration/>
</dashlet>
<dashlet id="DashletPlainText" _delta="define">
<label>UI:DashletPlainText:Label</label>
<icon>images/dashlets/icons8-text-box-48.png</icon>
<description>UI:DashletPlainText:Description</description>
<min_width>2</min_width>
<min_height>1</min_height>
<preferred_width>2</preferred_width>
<preferred_height>1</preferred_height>
<configuration/>
</dashlet>
</dashlets>
<property_types _delta="define">
<property_type id="Dashboard" xsi:type="Combodo-AbstractPropertyType"/>
<property_type id="DashboardGrid" xsi:type="Combodo-PropertyType">
<extends>Dashboard</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<label>Dashboard</label>
<nodes>
<node id="title" xsi:type="Combodo-ValueType-String">
<label>UI:DashboardEdit:DashboardTitle</label>
</node>
<node id="refresh" xsi:type="Combodo-ValueType-Choice"> <!-- Possible de le cacher, etc celui-ci nous met dedans -->
<label>UI:DashboardEdit:AutoReload</label>
<values>
<value id="0">
<label>No auto-refresh</label>
</value>
<value id="30">
<label>Every 30 seconds</label>
</value>
<value id="60">
<label>Every 1 minute</label>
</value>
<value id="300">
<label>Every 5 minutes</label>
</value>
<value id="600">
<label>Every 10 minutes</label>
</value>
<value id="1800">
<label>Every 30 minutes</label>
</value>
<value id="3600">
<label>Every 1 hour</label>
</value>
</values>
</node>
<node id="pos_dashlets" xsi:type="Combodo-ValueType-Collection">
<label>Dashlet List</label>
<xml-format xsi:type="Combodo-XMLFormat-CollectionWithId">
<tag-name>pos_dashlet</tag-name>
</xml-format>
<prototype>
<node id="position_x" xsi:type="Combodo-ValueType-Integer">
<label>X</label>
</node>
<node id="position_y" xsi:type="Combodo-ValueType-Integer">
<label>Y</label>
</node>
<node id="width" xsi:type="Combodo-ValueType-Integer">
<label>W</label>
</node>
<node id="height" xsi:type="Combodo-ValueType-Integer">
<label>H</label>
</node>
<node id="dashlet" xsi:type="Combodo-ValueType-Polymorphic">
<label>Dashlet</label>
<allowed-types>
<allowed-type>Dashlet</allowed-type>
</allowed-types>
</node>
</prototype>
</node>
</nodes>
</definition>
</property_type>
<property_type id="Dashlet" xsi:type="Combodo-AbstractPropertyType"/>
<property_type id="DashletGroupByTable" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<label>UI:DashletGroupBy:Title</label>
<nodes>
<node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletGroupBy:Prop-Title</label>
</node>
<node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletGroupBy:Prop-Query</label>
</node>
<node id="group_by" xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
<label>UI:DashletGroupBy:Prop-GroupBy</label>
<class>{{query.selected_class}}</class>
</node>
<node id="style" xsi:type="Combodo-ValueType-Choice"> <!-- Possible de le cacher, etc celui-ci nous met dedans -->
<label>UI:DashletGroupBy:Prop-Style</label>
<values>
<value id="bars">
<label>UI:DashletGroupByBars:Label</label>
</value>
<value id="pie">
<label>UI:DashletGroupByPie:Label</label>
</value>
<value id="table">
<label>UI:DashletGroupByTable:Label</label>
</value>
</values>
</node>
<node id="aggregation_function" xsi:type="Combodo-ValueType-AggregateFunction">
<label>UI:DashletGroupBy:Prop-Function</label>
<class>{{query.selected_class}}</class> <!-- pour savoir si il y a des attributs additionnables -->
</node>
<node id="aggregation_attribute" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:DashletGroupBy:Prop-FunctionAttribute</label>
<relevance-condition>{{aggregation_function.value != 'count'}}</relevance-condition>
<class>{{query.selected_class}}</class>
<category>numeric</category>
</node>
<node id="order_by" xsi:type="Combodo-ValueType-ChoiceFromInput">
<label>UI:DashletGroupBy:Prop-OrderField</label>
<values>
<value id="attribute">
<label>{{aggregation_attribute.label}}</label>
</value>
<value id="function">
<label>{{aggregation_function.label}}</label>
</value>
</values>
</node>
<node id="limit" xsi:type="Combodo-ValueType-Integer">
<label>UI:DashletGroupBy:Prop-Limit</label>
<relevance-condition>{{order_by.value = 'function'}}</relevance-condition>
</node>
<node id="order_direction" xsi:type="Combodo-ValueType-Choice">
<label>UI:DashletGroupBy:Prop-OrderDirection</label>
<values>
<value id="asc">
<label>UI:DashletGroupBy:Order:asc</label>
</value>
<value id="desc">
<label>UI:DashletGroupBy:Order:desc</label>
</value>
</values>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletGroupByBars" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<label>UI:DashletGroupBy:Title</label>
<nodes>
<node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletGroupBy:Prop-Title</label>
</node>
<node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletGroupBy:Prop-Query</label>
</node>
<node id="group_by" xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
<label>UI:DashletGroupBy:Prop-GroupBy</label>
<class>{{query.selected_class}}</class>
</node>
<node id="style" xsi:type="Combodo-ValueType-Choice"> <!-- Possible de le cacher, etc celui-ci nous met dedans -->
<label>UI:DashletGroupBy:Prop-Style</label>
<values>
<value id="bars">
<label>UI:DashletGroupByBars:Label</label>
</value>
<value id="pie">
<label>UI:DashletGroupByPie:Label</label>
</value>
<value id="table">
<label>UI:DashletGroupByTable:Label</label>
</value>
</values>
</node>
<node id="aggregation_function" xsi:type="Combodo-ValueType-AggregateFunction">
<label>UI:DashletGroupBy:Prop-Function</label>
<class>{{query.selected_class}}</class> <!-- pour savoir si il y a des attributs additionnables -->
</node>
<node id="aggregation_attribute" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:DashletGroupBy:Prop-FunctionAttribute</label>
<relevance-condition>{{aggregation_function.value != 'count'}}</relevance-condition>
<class>{{query.selected_class}}</class>
<category>numeric</category>
</node>
<node id="order_by" xsi:type="Combodo-ValueType-ChoiceFromInput">
<label>UI:DashletGroupBy:Prop-OrderField</label>
<values>
<value id="attribute">
<label>{{aggregation_attribute.label}}</label>
</value>
<value id="function">
<label>{{aggregation_function.label}}</label>
</value>
</values>
</node>
<node id="limit" xsi:type="Combodo-ValueType-Integer">
<label>UI:DashletGroupBy:Prop-Limit</label>
<relevance-condition>{{order_by.value = 'function'}}</relevance-condition>
</node>
<node id="order_direction" xsi:type="Combodo-ValueType-Choice">
<label>UI:DashletGroupBy:Prop-OrderDirection</label>
<values>
<value id="asc">
<label>UI:DashletGroupBy:Order:asc</label>
</value>
<value id="desc">
<label>UI:DashletGroupBy:Order:desc</label>
</value>
</values>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletGroupByPie" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<label>UI:DashletGroupBy:Title</label>
<nodes>
<node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletGroupBy:Prop-Title</label>
</node>
<node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletGroupBy:Prop-Query</label>
</node>
<node id="group_by" xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
<label>UI:DashletGroupBy:Prop-GroupBy</label>
<class>{{query.selected_class}}</class>
</node>
<node id="style" xsi:type="Combodo-ValueType-Choice"> <!-- Possible de le cacher, etc celui-ci nous met dedans -->
<label>UI:DashletGroupBy:Prop-Style</label>
<values>
<value id="bars">
<label>UI:DashletGroupByBars:Label</label>
</value>
<value id="pie">
<label>UI:DashletGroupByPie:Label</label>
</value>
<value id="table">
<label>UI:DashletGroupByTable:Label</label>
</value>
</values>
</node>
<node id="aggregation_function" xsi:type="Combodo-ValueType-AggregateFunction">
<label>UI:DashletGroupBy:Prop-Function</label>
<class>{{query.selected_class}}</class> <!-- pour savoir si il y a des attributs additionnables -->
</node>
<node id="aggregation_attribute" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:DashletGroupBy:Prop-FunctionAttribute</label>
<relevance-condition>{{aggregation_function.value != 'count'}}</relevance-condition>
<class>{{query.selected_class}}</class>
<category>numeric</category>
</node>
<node id="order_by" xsi:type="Combodo-ValueType-ChoiceFromInput">
<label>UI:DashletGroupBy:Prop-OrderField</label>
<values>
<value id="attribute">
<label>{{aggregation_attribute.label}}</label>
</value>
<value id="function">
<label>{{aggregation_function.label}}</label>
</value>
</values>
</node>
<node id="limit" xsi:type="Combodo-ValueType-Integer">
<label>UI:DashletGroupBy:Prop-Limit</label>
<relevance-condition>{{order_by.value = 'function'}}</relevance-condition>
</node>
<node id="order_direction" xsi:type="Combodo-ValueType-Choice">
<label>UI:DashletGroupBy:Prop-OrderDirection</label>
<values>
<value id="asc">
<label>UI:DashletGroupBy:Order:asc</label>
</value>
<value id="desc">
<label>UI:DashletGroupBy:Order:desc</label>
</value>
</values>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletBadge" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="class" xsi:type="Combodo-ValueType-Class">
<label>UI:DashletBadge:Prop-Class</label>
<categories-csv>bizmodel</categories-csv>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletHeaderDynamic" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<label>UI:DashletHeaderDynamic:Title</label>
<nodes>
<node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletHeaderDynamic:Prop-Title</label>
</node>
<node id="icon" xsi:type="Combodo-ValueType-Icon">
<label>UI:DashletHeaderDynamic:Prop-Icon</label>
</node>
<node id="subtitle" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletHeaderDynamic:Prop-Subtitle</label>
</node>
<node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletHeaderDynamic:Prop-Query</label>
</node>
<node id="group_by" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:DashletHeaderDynamic:Prop-GroupBy</label>
<class>{{query.selected_class}}</class>
<category>enum</category>
</node>
<node id="values" xsi:type="Combodo-ValueType-CollectionOfValues">
<label>UI:DashletHeaderDynamic:Prop-Values</label>
<xml-format xsi:type="Combodo-XMLFormat-CSV"/>
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
<class>{{query.selected_class}}</class>
<attribute>{{group_by.attribute}}</attribute>
</value-type>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletHeaderStatic" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletHeaderStatic:Prop-Title</label>
</node>
<node id="icon" xsi:type="Combodo-ValueType-Icon">
<label>UI:DashletHeaderStatic:Prop-Icon</label>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletObjectList" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletObjectList:Prop-Title</label>
</node>
<node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletObjectList:Prop-Query</label>
</node>
<node id="menu" xsi:type="Combodo-ValueType-Boolean">
<label>UI:DashletObjectList:Prop-Menu</label>
<on>
<!-- not so cute, but matches exactly 3.2 implementation of boolean fields -->
<label>UI:UserManagement:ActionAllowed:Yes</label>
<value>true</value>
</on>
<off>
<label>UI:UserManagement:ActionAllowed:No</label>
<value>false</value>
</off>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletPlainText" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="text" xsi:type="Combodo-ValueType-Text">
<label>UI:DashletPlainText:Prop-Text</label>
</node>
</nodes>
</definition>
</property_type>
</property_types>
</meta>
</itop_design>

View File

@@ -6,6 +6,7 @@
*/
use Combodo\iTop\Application\Helper\WebResourcesHelper;
use Combodo\iTop\Application\UI\Base\Layout\PageContent\PageContentFactory;
use Combodo\iTop\Application\WebPage\ErrorPage;
use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
@@ -1279,13 +1280,14 @@ class DashboardMenuNode extends MenuNode
if ($oDashboard != null) {
WebResourcesHelper::EnableC3JSToWebPage($oPage);
// TODO 3.3 this works for dashboard menu, what about other places ?
$oPageLayout = PageContentFactory::MakeForDashboard();
$oPage->SetContentLayout($oPageLayout, $oPage);
$sDivId = utils::Sanitize($this->sMenuId, '', 'element_identifier');
$oPage->add('<div id="'.$sDivId.'" class="ibo-dashboard" data-role="ibo-dashboard">');
$aExtraParams['dashboard_div_id'] = $sDivId;
$aExtraParams['from_dashboard_page'] = true;
$oDashboard->SetReloadURL($this->GetHyperlink($aExtraParams));
$oDashboard->Render($oPage, false, $aExtraParams);
$oPage->add('</div>');
$bEdit = utils::ReadParam('edit', false);
if ($bEdit) {

View File

@@ -1900,6 +1900,12 @@ SQL;
return $response;
}
public static function QuoteForPHP(string $sValue): string
{
$sEscaped = str_replace(['\\', "'"], ['\\\\', "\\'"], $sValue);
return "'$sEscaped'";
}
/**
* Get a standard list of character sets
*

View File

@@ -31,6 +31,7 @@
"symfony/mailer": "^6.4",
"symfony/security-csrf": "^6.4",
"symfony/twig-bundle": "~6.4.0",
"symfony/validator" : "^6.4",
"symfony/yaml": "~6.4.0",
"tecnickcom/tcpdf": "^6.6.0",
"thenetworg/oauth2-azure": "^2.0"

103
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "26fa7aa920057d080bcc0948bf052fda",
"content-hash" : "3e627286597661542dd598499c2bcc36",
"packages": [
{
"name": "apereo/phpcas",
@@ -4984,6 +4984,107 @@
"time": "2025-07-10T08:14:14+00:00"
},
{
"name" : "symfony/validator",
"version" : "v6.4.29",
"source" : {
"type" : "git",
"url" : "https://github.com/symfony/validator.git",
"reference" : "99df8a769e64e399f510166141ea74f450e8dd1d"
},
"dist" : {
"type" : "zip",
"url" : "https://api.github.com/repos/symfony/validator/zipball/99df8a769e64e399f510166141ea74f450e8dd1d",
"reference" : "99df8a769e64e399f510166141ea74f450e8dd1d",
"shasum" : ""
},
"require" : {
"php" : ">=8.1",
"symfony/deprecation-contracts" : "^2.5|^3",
"symfony/polyfill-ctype" : "~1.8",
"symfony/polyfill-mbstring" : "~1.0",
"symfony/polyfill-php83" : "^1.27",
"symfony/translation-contracts" : "^2.5|^3"
},
"conflict" : {
"doctrine/annotations" : "<1.13",
"doctrine/lexer" : "<1.1",
"symfony/dependency-injection" : "<5.4",
"symfony/expression-language" : "<5.4",
"symfony/http-kernel" : "<5.4",
"symfony/intl" : "<5.4",
"symfony/property-info" : "<5.4",
"symfony/translation" : "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3",
"symfony/yaml" : "<5.4"
},
"require-dev" : {
"doctrine/annotations" : "^1.13|^2",
"egulias/email-validator" : "^2.1.10|^3|^4",
"symfony/cache" : "^5.4|^6.0|^7.0",
"symfony/config" : "^5.4|^6.0|^7.0",
"symfony/console" : "^5.4|^6.0|^7.0",
"symfony/dependency-injection" : "^5.4|^6.0|^7.0",
"symfony/expression-language" : "^5.4|^6.0|^7.0",
"symfony/finder" : "^5.4|^6.0|^7.0",
"symfony/http-client" : "^5.4|^6.0|^7.0",
"symfony/http-foundation" : "^5.4|^6.0|^7.0",
"symfony/http-kernel" : "^5.4|^6.0|^7.0",
"symfony/intl" : "^5.4|^6.0|^7.0",
"symfony/mime" : "^5.4|^6.0|^7.0",
"symfony/property-access" : "^5.4|^6.0|^7.0",
"symfony/property-info" : "^5.4|^6.0|^7.0",
"symfony/translation" : "^5.4.35|~6.3.12|^6.4.3|^7.0.3",
"symfony/yaml" : "^5.4|^6.0|^7.0"
},
"type" : "library",
"autoload" : {
"psr-4" : {
"Symfony\\Component\\Validator\\" : ""
},
"exclude-from-classmap" : [
"/Tests/",
"/Resources/bin/"
]
},
"notification-url" : "https://packagist.org/downloads/",
"license" : [
"MIT"
],
"authors" : [
{
"name" : "Fabien Potencier",
"email" : "fabien@symfony.com"
},
{
"name" : "Symfony Community",
"homepage" : "https://symfony.com/contributors"
}
],
"description" : "Provides tools to validate values",
"homepage" : "https://symfony.com",
"support" : {
"source" : "https://github.com/symfony/validator/tree/v6.4.29"
},
"funding" : [
{
"url" : "https://symfony.com/sponsor",
"type" : "custom"
},
{
"url" : "https://github.com/fabpot",
"type" : "github"
},
{
"url" : "https://github.com/nicolas-grekas",
"type" : "github"
},
{
"url" : "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type" : "tidelift"
}
],
"time" : "2025-11-06T20:26:06+00:00"
},
{
"name": "symfony/var-dumper",
"version": "v6.4.26",
"source": {

View File

@@ -24,7 +24,7 @@ MetaModel::IncludeModule('application/user.dashboard.class.inc.php');
MetaModel::IncludeModule('application/audit.rule.class.inc.php');
MetaModel::IncludeModule('application/audit.domain.class.inc.php');
MetaModel::IncludeModule('application/query.class.inc.php');
MetaModel::IncludeModule('setup/moduleinstallation/moduleinstallation.class.inc.php');
MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php');
MetaModel::IncludeModule('core/event.class.inc.php');
MetaModel::IncludeModule('core/action.class.inc.php');

View File

@@ -2685,13 +2685,14 @@ class Config
*
* @param array $aParamValues
* @param ?string $sModulesDir
* @param bool $bPreserveModuleSettings
*
* @return void The current object is modified directly
*
* @throws \Exception
* @throws \CoreException
*/
public function UpdateFromParams($aParamValues, $sModulesDir = null)
public function UpdateFromParams($aParamValues, $sModulesDir = null, $bPreserveModuleSettings = false)
{
if (isset($aParamValues['application_path'])) {
$this->Set('app_root_url', $aParamValues['application_path']);
@@ -2739,10 +2740,7 @@ class Config
} else {
$aSelectedModules = null;
}
if (! is_null($sModulesDir)) {
$this->UpdateIncludes($sModulesDir, $aSelectedModules);
}
$this->UpdateIncludes($sModulesDir, $aSelectedModules);
if (isset($aParamValues['source_dir'])) {
$this->Set('source_dir', $aParamValues['source_dir']);
@@ -2760,13 +2758,17 @@ class Config
*
* @throws Exception
*/
public function UpdateIncludes(string $sModulesDir, $aSelectedModules = null)
public function UpdateIncludes($sModulesDir, $aSelectedModules = null)
{
if ($sModulesDir === null) {
return;
}
// Initialize the arrays below with default values for the application...
$oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values
$aAddOns = $oEmptyConfig->GetAddOns();
$aModules = ModuleDiscovery::GetModulesOrderedByDependencies([APPROOT.$sModulesDir]);
$aModules = ModuleDiscovery::GetAvailableModules([APPROOT.$sModulesDir]);
foreach ($aModules as $sModuleId => $aModuleInfo) {
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
if (is_null($aSelectedModules) || in_array($sModuleName, $aSelectedModules)) {

View File

@@ -41,7 +41,7 @@ use utils;
/**
* Class \Combodo\iTop\DesignDocument
*
* A design document is the DOM tree that modelize behaviors. One of its
* A design document is the DOM tree that models behaviors. One of its
* characteristics is that it can be altered by the mean of the same kind of document.
*
*/

View File

@@ -691,6 +691,28 @@ abstract class LogAPI
static::$m_oMockMetaModelConfig = $oMetaModelConfig;
}
public static function Exception(string $sMessage, throwable $oException, string $sChannel = null, array $aContext = []): void
{
$aErrorLogs = [];
$aErrorLogs[] = static::PrepareErrorLog($sMessage, $oException, $aContext);
$oException = $oException->getPrevious();
while ($oException !== null) {
$aErrorLogs[] = static::PrepareErrorLog($oException->getMessage(), $oException, $aContext, true);
$oException = $oException->getPrevious();
}
$aErrorLogs = array_reverse($aErrorLogs);
foreach ($aErrorLogs as $aErrorLog) {
static::Error($aErrorLog['message'], $sChannel, $aErrorLog['context']);
}
}
private static function PrepareErrorLog(string $sMessage, throwable $oException, array $aContext, bool $isPrevious = false): array
{
$aContext['Error Message'] = $oException->getMessage();
$aContext['Stack Trace'] = $oException->getTraceAsString();
return ['message' => ($isPrevious ? "Previous " : '')."Exception: $sMessage", 'context' => $aContext];
}
public static function Error($sMessage, $sChannel = null, $aContext = [])
{
static::Log(self::LEVEL_ERROR, $sMessage, $sChannel, $aContext);

View File

@@ -22,8 +22,6 @@ use Combodo\iTop\Application\EventRegister\ApplicationEvents;
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
use Combodo\iTop\Service\Events\EventData;
use Combodo\iTop\Service\Events\EventService;
use Combodo\iTop\Setup\ModuleDependency\Module;
use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader;
require_once APPROOT.'core/modulehandler.class.inc.php';
require_once APPROOT.'core/querymodifier.class.inc.php';
@@ -464,43 +462,6 @@ abstract class MetaModel
return call_user_func([$sClass, 'GetClassDescription'], $sClass);
}
/**
* @param string $sClass
*
* @return string
* @throws \CoreException
*/
final public static function GetModuleName($sClass)
{
try {
$oReflectionClass = new ReflectionClass($sClass);
$sDir = realpath(dirname($oReflectionClass->getFileName()));
$sApproot = realpath(APPROOT);
while (($sDir !== $sApproot) && (str_contains($sDir, $sApproot))) {
$aFiles = glob("$sDir/module.*.php");
if (count($aFiles) > 1) {
return 'core';
}
if (count($aFiles) == 0) {
$sDir = realpath(dirname($sDir));
continue;
}
$sModuleFilePath = $aFiles[0];
$aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sModuleFilePath);
$sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID];
list($sModuleName, ) = ModuleDiscovery::GetModuleName($sModuleId);
return $sModuleName;
}
} catch (\Exception $e) {
throw new CoreException("Cannot find class module", ['class' => $sClass], '', $e);
}
return 'core';
}
/**
* @param string $sClass
*

View File

@@ -55,6 +55,11 @@ abstract class ModelReflection
abstract public function GetFiltersList($sClass);
abstract public function IsValidFilterCode($sClass, $sFilterCode);
/**
* @since 3.3.0
*/
abstract public function IsAbstract($sClass): bool;
/**
* @param string $sOQL
*
@@ -84,9 +89,17 @@ abstract class ModelReflection
* @param string $defaultValue
*
* @return \RunTimeIconSelectionField
* @deprecated since 3.3.0 replaced by GetAvailableIcons
*/
abstract public function GetIconSelectionField($sCode, $sLabel = '', $defaultValue = '');
/**
* Find available icons for the current context
*
* @return array of ['value', 'label', 'icon'] where 'value' is the relative path on disk, 'label' the name to display and 'icon' is the URL to get the image
*/
abstract public function GetAvailableIcons(): array;
abstract public function GetRootClass($sClass);
abstract public function EnumChildClasses($sClass, $iOption = ENUM_CHILD_CLASSES_EXCLUDETOP);
}
@@ -104,6 +117,8 @@ abstract class QueryReflection
class ModelReflectionRuntime extends ModelReflection
{
private static array $aAllIcons = [];
public function __construct()
{
}
@@ -148,7 +163,7 @@ class ModelReflectionRuntime extends ModelReflection
$sAttributeClass = get_class($oAttDef);
if ($aScope != null) {
foreach ($aScope as $sScopeClass) {
if (($sAttributeClass == $sScopeClass) || is_subclass_of($sAttributeClass, $sScopeClass)) {
if (is_a($sAttributeClass, $sScopeClass, true)) {
$aAttributes[$sAttCode] = $sAttributeClass;
break;
}
@@ -230,6 +245,11 @@ class ModelReflectionRuntime extends ModelReflection
return MetaModel::IsValidFilterCode($sClass, $sFilterCode);
}
public function IsAbstract($sClass): bool
{
return MetaModel::IsAbstract($sClass);
}
public function GetQuery($sOQL)
{
return new QueryReflectionRuntime($sOQL, $this);
@@ -245,6 +265,52 @@ class ModelReflectionRuntime extends ModelReflection
return new RunTimeIconSelectionField($sCode, $sLabel, $defaultValue);
}
public function GetAvailableIcons(): array
{
$aFolderList = [
APPROOT.'env-'.utils::GetCurrentEnvironment() => utils::GetAbsoluteUrlModulesRoot(),
APPROOT.'images/icons' => utils::GetAbsoluteUrlAppRoot().'images/icons',
];
if (count(self::$aAllIcons) == 0) {
foreach ($aFolderList as $sFolderPath => $sUrlPrefix) {
$aIcons = self::FindIconsOnDisk($sFolderPath);
ksort($aIcons);
foreach ($aIcons as $sFilePath) {
self::$aAllIcons[] = ['value' => $sFilePath, 'label' => basename($sFilePath), 'icon' => $sUrlPrefix.$sFilePath];
}
}
}
return self::$aAllIcons;
}
private static function FindIconsOnDisk(string $sBaseDir, string $sDir = '', array &$aFilesSpecs = []): array
{
$aResult = [];
// Populate automatically the list of icon files
if ($hDir = @opendir($sBaseDir.'/'.$sDir)) {
while (($sFile = readdir($hDir)) !== false) {
$aMatches = [];
if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile)) {
$sDirSubPath = ($sDir == '') ? $sFile : $sDir.'/'.$sFile;
$aResult = array_merge($aResult, self::FindIconsOnDisk($sBaseDir, $sDirSubPath, $aFilesSpecs));
}
$sSize = filesize($sBaseDir.'/'.$sDir.'/'.$sFile);
if (isset($aFilesSpecs[$sFile]) && $aFilesSpecs[$sFile] == $sSize) {
continue;
}
if (preg_match('/\.(png|jpg|jpeg|gif|svg)$/i', $sFile, $aMatches)) { // png, jp(e)g, gif and svg are considered valid
$aResult[$sFile.'_'.$sDir] = $sDir.'/'.$sFile;
$aFilesSpecs[$sFile] = $sSize;
}
}
closedir($hDir);
}
return $aResult;
}
public function GetRootClass($sClass)
{
return MetaModel::GetRootClass($sClass);

View File

@@ -2103,12 +2103,18 @@ class VariableExpression extends UnaryExpression
/**
* Evaluate the value of the expression
*
* @param array $aArgs
* @throws \Exception if terms cannot be evaluated as scalars
*/
*
* @return mixed
* @throws \MissingQueryArgument
*/
public function Evaluate(array $aArgs)
{
throw new Exception('not implemented yet');
if (!isset($aArgs[$this->m_sName])) {
throw new MissingQueryArgument('Missing variable expression argument', array('expecting'=>$this->m_sName));
}
return $aArgs[$this->m_sName];
}
/**

View File

@@ -72,9 +72,15 @@ class OQLException extends CoreException
}
else
{
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
$sMessage = "$sIssue - found '{$this->m_sUnexpected}' at $iCol in '$sInput'";
if (count($this->m_aExpecting) < 30) {
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
$sMessage .= ', expecting '.json_encode($sExpectations);
}
$sSuggest = self::FindClosestString($this->m_sUnexpected, $this->m_aExpecting);
$sMessage = "$sIssue - found '{$this->m_sUnexpected}' at $iCol in '$sInput', expecting $sExpectations, I would suggest to use '$sSuggest'";
if (strlen($sSuggest) > 0) {
$sMessage .= ", I would suggest to use ".json_encode($sSuggest);
}
}
// make sure everything is assigned properly
@@ -155,5 +161,3 @@ class OQLException extends CoreException
return $sRet;
}
}
?>

View File

@@ -57,15 +57,15 @@ class OqlName
{
return $this->m_iPos;
}
public function __toString()
{
return $this->m_sValue;
}
}
}
/**
*
*
* Store hexadecimal values as strings so that we can support 64-bit values
*
*/
@@ -77,12 +77,12 @@ class OqlHexValue
{
$this->m_sValue = $sValue;
}
public function __toString()
{
return $this->m_sValue;
}
}
class OqlJoinSpec
@@ -109,6 +109,7 @@ class OqlJoinSpec
{
return $this->m_oClass->GetValue();
}
public function GetClassAlias()
{
return $this->m_oClassAlias->GetValue();
@@ -118,6 +119,7 @@ class OqlJoinSpec
{
return $this->m_oClass;
}
public function GetClassAliasDetails()
{
return $this->m_oClassAlias;
@@ -127,10 +129,12 @@ class OqlJoinSpec
{
return $this->m_oLeftField;
}
public function GetRightField()
{
return $this->m_oRightField;
}
public function GetOperator()
{
return $this->m_sOperator;
@@ -146,8 +150,9 @@ interface CheckableExpression
* @param ModelReflection $oModelReflection MetaModel to consider
* @param array $aAliases Aliases to class names (for the current query)
* @param string $sSourceQuery For the reporting
*
* @throws OqlNormalizeException
*/
*/
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery);
}
@@ -168,13 +173,11 @@ class MatchOqlExpression extends MatchExpression implements CheckableExpression
$this->m_oRightExpr->Check($oModelReflection, $aAliases, $sSourceQuery);
// Only field MATCHES scalar is allowed
if (!$this->m_oLeftExpr instanceof FieldExpression)
{
if (!$this->m_oLeftExpr instanceof FieldExpression) {
throw new OqlNormalizeException('Only "field MATCHES string" syntax is allowed', $sSourceQuery, new OqlName($this->m_oLeftExpr->RenderExpression(true), 0));
}
// Only field MATCHES scalar is allowed
if (!$this->m_oRightExpr instanceof ScalarExpression && !$this->m_oRightExpr instanceof VariableOqlExpression)
{
if (!$this->m_oRightExpr instanceof ScalarExpression && !$this->m_oRightExpr instanceof VariableOqlExpression) {
throw new OqlNormalizeException('Only "field MATCHES string" syntax is allowed', $sSourceQuery, new OqlName($this->m_oRightExpr->RenderExpression(true), 0));
}
}
@@ -198,7 +201,7 @@ class NestedQueryOqlExpression extends NestedQueryExpression implements Checkabl
*
* @param OQLObjectQuery $oOQLObjectQuery
*/
public function __construct($oOQLObjectQuery )
public function __construct($oOQLObjectQuery)
{
parent::__construct($oOQLObjectQuery->ToDBSearch(""));
$this->m_oOQLObjectQuery = $oOQLObjectQuery;
@@ -232,8 +235,7 @@ class FieldOqlExpression extends FieldExpression implements CheckableExpression
public function __construct($oName, $oParent = null)
{
if (is_null($oParent))
{
if (is_null($oParent)) {
$oParent = new OqlName('', 0);
}
$this->m_oParent = $oParent;
@@ -256,37 +258,28 @@ class FieldOqlExpression extends FieldExpression implements CheckableExpression
{
$sClassAlias = $this->GetParent();
$sFltCode = $this->GetName();
if (empty($sClassAlias))
{
if (empty($sClassAlias)) {
// Try to find an alias
// Build an array of field => array of aliases
$aFieldClasses = array();
foreach($aAliases as $sAlias => $sReal)
{
foreach($oModelReflection->GetFiltersList($sReal) as $sAnFltCode)
{
foreach ($aAliases as $sAlias => $sReal) {
foreach ($oModelReflection->GetFiltersList($sReal) as $sAnFltCode) {
$aFieldClasses[$sAnFltCode][] = $sAlias;
}
}
if (!array_key_exists($sFltCode, $aFieldClasses))
{
if (!array_key_exists($sFltCode, $aFieldClasses)) {
throw new OqlNormalizeException('Unknown filter code', $sSourceQuery, $this->GetNameDetails(), array_keys($aFieldClasses));
}
if (count($aFieldClasses[$sFltCode]) > 1)
{
if (count($aFieldClasses[$sFltCode]) > 1) {
throw new OqlNormalizeException('Ambiguous filter code', $sSourceQuery, $this->GetNameDetails());
}
$sClassAlias = $aFieldClasses[$sFltCode][0];
}
else
{
if (!array_key_exists($sClassAlias, $aAliases))
{
} else {
if (!array_key_exists($sClassAlias, $aAliases)) {
throw new OqlNormalizeException('Unknown class [alias]', $sSourceQuery, $this->GetParentDetails(), array_keys($aAliases));
}
$sClass = $aAliases[$sClassAlias];
if (!$oModelReflection->IsValidFilterCode($sClass, $sFltCode))
{
if (!$oModelReflection->IsValidFilterCode($sClass, $sFltCode)) {
throw new OqlNormalizeException('Unknown filter code', $sSourceQuery, $this->GetNameDetails(), $oModelReflection->GetFiltersList($sClass));
}
}
@@ -305,8 +298,7 @@ class ListOqlExpression extends ListExpression implements CheckableExpression
{
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
{
foreach ($this->GetItems() as $oItemExpression)
{
foreach ($this->GetItems() as $oItemExpression) {
$oItemExpression->Check($oModelReflection, $aAliases, $sSourceQuery);
}
}
@@ -316,8 +308,7 @@ class FunctionOqlExpression extends FunctionExpression implements CheckableExpre
{
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
{
foreach ($this->GetArgs() as $oArgExpression)
{
foreach ($this->GetArgs() as $oArgExpression) {
$oArgExpression->Check($oModelReflection, $aAliases, $sSourceQuery);
}
}
@@ -350,6 +341,7 @@ abstract class OqlQuery
* Determine the class
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @return string
* @throws Exception
*/
@@ -392,6 +384,7 @@ class OqlObjectQuery extends OqlQuery
* Determine the class
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @return string
* @throws Exception
*/
@@ -415,6 +408,7 @@ class OqlObjectQuery extends OqlQuery
{
return $this->m_oClass;
}
public function GetClassAliasDetails()
{
return $this->m_oClassAlias;
@@ -424,6 +418,7 @@ class OqlObjectQuery extends OqlQuery
{
return $this->m_aJoins;
}
public function GetCondition()
{
return $this->m_oCondition;
@@ -432,44 +427,37 @@ class OqlObjectQuery extends OqlQuery
/**
* Recursively check the validity of the expression with regard to the data model
* and the query in which it is used
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @throws OqlNormalizeException
*/
*/
public function Check(ModelReflection $oModelReflection, $sSourceQuery, $aParentAliases = array())
{
$sClass = $this->GetClass($oModelReflection);
$sClassAlias = $this->GetClassAlias();
if (!$oModelReflection->IsValidClass($sClass))
{
if (!$oModelReflection->IsValidClass($sClass)) {
throw new UnknownClassOqlException($sSourceQuery, $this->GetClassDetails(), $oModelReflection->GetClasses());
}
$aAliases = array_merge(array($sClassAlias => $sClass),$aParentAliases);
$aAliases = array_merge(array($sClassAlias => $sClass), $aParentAliases);
$aJoinSpecs = $this->GetJoins();
if (is_array($aJoinSpecs))
{
foreach ($aJoinSpecs as $oJoinSpec)
{
if (is_array($aJoinSpecs)) {
foreach ($aJoinSpecs as $oJoinSpec) {
$sJoinClass = $oJoinSpec->GetClass();
$sJoinClassAlias = $oJoinSpec->GetClassAlias();
if (!$oModelReflection->IsValidClass($sJoinClass))
{
if (!$oModelReflection->IsValidClass($sJoinClass)) {
throw new UnknownClassOqlException($sSourceQuery, $oJoinSpec->GetClassDetails(), $oModelReflection->GetClasses());
}
if (array_key_exists($sJoinClassAlias, $aAliases))
{
if ($sJoinClassAlias != $sJoinClass)
{
if (array_key_exists($sJoinClassAlias, $aAliases)) {
if ($sJoinClassAlias != $sJoinClass) {
throw new OqlNormalizeException('Duplicate class alias', $sSourceQuery, $oJoinSpec->GetClassAliasDetails());
}
else
{
} else {
throw new OqlNormalizeException('Duplicate class name', $sSourceQuery, $oJoinSpec->GetClassDetails());
}
}
}
// Assumption: ext key on the left only !!!
// normalization should take care of this
@@ -480,85 +468,74 @@ class OqlObjectQuery extends OqlQuery
$oRightField = $oJoinSpec->GetRightField();
$sToClass = $oRightField->GetParent();
$sPKeyDescriptor = $oRightField->GetName();
if ($sPKeyDescriptor != 'id')
{
if ($sPKeyDescriptor != 'id') {
throw new OqlNormalizeException('Wrong format for Join clause (right hand), expecting an id', $sSourceQuery, $oRightField->GetNameDetails(), array('id'));
}
$aAliases[$sJoinClassAlias] = $sJoinClass;
if (!array_key_exists($sFromClass, $aAliases))
{
if (!array_key_exists($sFromClass, $aAliases)) {
throw new OqlNormalizeException('Unknown class in join condition (left expression)', $sSourceQuery, $oLeftField->GetParentDetails(), array_keys($aAliases));
}
if (!array_key_exists($sToClass, $aAliases))
{
if (!array_key_exists($sToClass, $aAliases)) {
throw new OqlNormalizeException('Unknown class in join condition (right expression)', $sSourceQuery, $oRightField->GetParentDetails(), array_keys($aAliases));
}
$aExtKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], \Combodo\iTop\Core\AttributeDefinition\AttributeExternalKey::class);
$aObjKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], \Combodo\iTop\Core\AttributeDefinition\AttributeObjectKey::class);
$aAllKeys = array_merge($aExtKeys, $aObjKeys);
if (!array_key_exists($sExtKeyAttCode, $aAllKeys))
{
if (!array_key_exists($sExtKeyAttCode, $aAllKeys)) {
throw new OqlNormalizeException('Unknown key in join condition (left expression)', $sSourceQuery, $oLeftField->GetNameDetails(), array_keys($aAllKeys));
}
if ($sFromClass == $sJoinClassAlias)
{
if ($sFromClass == $sJoinClassAlias) {
if (array_key_exists($sExtKeyAttCode, $aExtKeys)) // Skip that check for object keys
{
$sTargetClass = $oModelReflection->GetAttributeProperty($aAliases[$sFromClass], $sExtKeyAttCode, 'targetclass');
if(!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass))
{
if (!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass)) {
throw new OqlNormalizeException("The joined class ($aAliases[$sFromClass]) is not compatible with the external key, which is pointing to $sTargetClass", $sSourceQuery, $oLeftField->GetNameDetails());
}
}
}
else
{
} else {
$sOperator = $oJoinSpec->GetOperator();
switch($sOperator)
{
switch ($sOperator) {
case '=':
$iOperatorCode = TREE_OPERATOR_EQUALS;
break;
$iOperatorCode = TREE_OPERATOR_EQUALS;
break;
case 'BELOW':
$iOperatorCode = TREE_OPERATOR_BELOW;
break;
$iOperatorCode = TREE_OPERATOR_BELOW;
break;
case 'BELOW_STRICT':
$iOperatorCode = TREE_OPERATOR_BELOW_STRICT;
break;
$iOperatorCode = TREE_OPERATOR_BELOW_STRICT;
break;
case 'NOT_BELOW':
$iOperatorCode = TREE_OPERATOR_NOT_BELOW;
break;
$iOperatorCode = TREE_OPERATOR_NOT_BELOW;
break;
case 'NOT_BELOW_STRICT':
$iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT;
break;
$iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT;
break;
case 'ABOVE':
$iOperatorCode = TREE_OPERATOR_ABOVE;
break;
$iOperatorCode = TREE_OPERATOR_ABOVE;
break;
case 'ABOVE_STRICT':
$iOperatorCode = TREE_OPERATOR_ABOVE_STRICT;
break;
$iOperatorCode = TREE_OPERATOR_ABOVE_STRICT;
break;
case 'NOT_ABOVE':
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE;
break;
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE;
break;
case 'NOT_ABOVE_STRICT':
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT;
break;
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT;
break;
}
if (array_key_exists($sExtKeyAttCode, $aExtKeys)) // Skip that check for object keys
{
$sTargetClass = $oModelReflection->GetAttributeProperty($aAliases[$sFromClass], $sExtKeyAttCode, 'targetclass');
if(!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass))
{
if (!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass)) {
throw new OqlNormalizeException("The joined class ($aAliases[$sToClass]) is not compatible with the external key, which is pointing to $sTargetClass", $sSourceQuery, $oLeftField->GetNameDetails());
}
}
$aAttList = $oModelReflection->ListAttributes($aAliases[$sFromClass]);
$sAttType = $aAttList[$sExtKeyAttCode];
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !is_subclass_of($sAttType, \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class) && ($sAttType != \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class))
{
if (($iOperatorCode != TREE_OPERATOR_EQUALS) && !is_a($sAttType, \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class, true)) {
throw new OqlNormalizeException("The specified tree operator $sOperator is not applicable to the key", $sSourceQuery, $oLeftField->GetNameDetails());
}
}
@@ -567,26 +544,23 @@ class OqlObjectQuery extends OqlQuery
// Check the select information
//
foreach ($this->GetSelectedClasses() as $oClassDetails)
{
foreach ($this->GetSelectedClasses() as $oClassDetails) {
$sClassToSelect = $oClassDetails->GetValue();
if (!array_key_exists($sClassToSelect, $aAliases))
{
if (!array_key_exists($sClassToSelect, $aAliases)) {
throw new OqlNormalizeException('Unknown class [alias]', $sSourceQuery, $oClassDetails, array_keys($aAliases));
}
}
// Check the condition tree
//
if ($this->m_oCondition instanceof Expression)
{
if ($this->m_oCondition instanceof Expression) {
$this->m_oCondition->Check($oModelReflection, $aAliases, $sSourceQuery);
}
}
/**
* Make the relevant DBSearch instance (FromOQL)
*/
*/
public function ToDBSearch($sQuery)
{
$sClass = $this->GetClass(new ModelReflectionRuntime());
@@ -594,6 +568,7 @@ class OqlObjectQuery extends OqlQuery
$oSearch = new DBObjectSearch($sClass, $sClassAlias);
$oSearch->InitFromOqlQuery($this, $sQuery);
return $oSearch;
}
}
@@ -606,19 +581,15 @@ class OqlUnionQuery extends OqlQuery
{
parent::__construct();
$this->aQueries[] = $oLeftQuery;
if ($oRightQueryOrUnion instanceof OqlUnionQuery)
{
foreach ($oRightQueryOrUnion->GetQueries() as $oSingleQuery)
{
if ($oRightQueryOrUnion instanceof OqlUnionQuery) {
foreach ($oRightQueryOrUnion->GetQueries() as $oSingleQuery) {
$this->aQueries[] = $oSingleQuery;
}
}
else
{
} else {
$this->aQueries[] = $oRightQueryOrUnion;
}
}
public function GetQueries()
{
return $this->aQueries;
@@ -627,66 +598,54 @@ class OqlUnionQuery extends OqlQuery
/**
* Check the validity of the expression with regard to the data model
* and the query in which it is used
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @throws OqlNormalizeException
*/
*/
public function Check(ModelReflection $oModelReflection, $sSourceQuery)
{
$aColumnToClasses = array();
foreach ($this->aQueries as $iQuery => $oQuery)
{
foreach ($this->aQueries as $iQuery => $oQuery) {
$oQuery->Check($oModelReflection, $sSourceQuery);
$aAliasToClass = array($oQuery->GetClassAlias() => $oQuery->GetClass($oModelReflection));
$aJoinSpecs = $oQuery->GetJoins();
if (is_array($aJoinSpecs))
{
foreach ($aJoinSpecs as $oJoinSpec)
{
if (is_array($aJoinSpecs)) {
foreach ($aJoinSpecs as $oJoinSpec) {
$aAliasToClass[$oJoinSpec->GetClassAlias()] = $oJoinSpec->GetClass();
}
}
$aSelectedClasses = $oQuery->GetSelectedClasses();
if ($iQuery != 0)
{
if (count($aSelectedClasses) < count($aColumnToClasses))
{
if ($iQuery != 0) {
if (count($aSelectedClasses) < count($aColumnToClasses)) {
$oLastClass = end($aSelectedClasses);
throw new OqlNormalizeException('Too few selected classes in the subquery', $sSourceQuery, $oLastClass);
}
if (count($aSelectedClasses) > count($aColumnToClasses))
{
if (count($aSelectedClasses) > count($aColumnToClasses)) {
$oLastClass = end($aSelectedClasses);
throw new OqlNormalizeException('Too many selected classes in the subquery', $sSourceQuery, $oLastClass);
}
}
foreach ($aSelectedClasses as $iColumn => $oClassDetails)
{
foreach ($aSelectedClasses as $iColumn => $oClassDetails) {
$sAlias = $oClassDetails->GetValue();
$sClass = $aAliasToClass[$sAlias];
$aColumnToClasses[$iColumn][] = array(
'alias' => $sAlias,
'class' => $sClass,
'alias' => $sAlias,
'class' => $sClass,
'class_name' => $oClassDetails,
);
}
}
foreach ($aColumnToClasses as $iColumn => $aClasses)
{
foreach ($aColumnToClasses as $iColumn => $aClasses) {
$sRootClass = null;
foreach ($aClasses as $iQuery => $aData)
{
if ($iQuery == 0)
{
foreach ($aClasses as $iQuery => $aData) {
if ($iQuery == 0) {
// Establish the reference
$sRootClass = $oModelReflection->GetRootClass($aData['class']);
}
else
{
if ($oModelReflection->GetRootClass($aData['class']) != $sRootClass)
{
} else {
if ($oModelReflection->GetRootClass($aData['class']) != $sRootClass) {
$aSubclasses = $oModelReflection->EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL);
throw new OqlNormalizeException('Incompatible classes: could not find a common ancestor', $sSourceQuery, $aData['class_name'], $aSubclasses);
}
@@ -699,21 +658,21 @@ class OqlUnionQuery extends OqlQuery
* Determine the class
*
* @param ModelReflection $oModelReflection MetaModel to consider
*
* @return string
* @throws Exception
*/
public function GetClass(ModelReflection $oModelReflection)
{
$aFirstColClasses = array();
foreach ($this->aQueries as $iQuery => $oQuery)
{
foreach ($this->aQueries as $iQuery => $oQuery) {
$aFirstColClasses[] = $oQuery->GetClass($oModelReflection);
}
$sClass = self::GetLowestCommonAncestor($oModelReflection, $aFirstColClasses);
if (is_null($sClass))
{
if (is_null($sClass)) {
throw new Exception('Could not determine the class of the union query. This issue should have been detected earlier by calling OqlQuery::Check()');
}
return $sClass;
}
@@ -726,6 +685,7 @@ class OqlUnionQuery extends OqlQuery
public function GetClassAlias()
{
$sAlias = $this->aQueries[0]->GetClassAlias();
return $sAlias;
}
@@ -735,29 +695,25 @@ class OqlUnionQuery extends OqlQuery
*
* @param ModelReflection $oModelReflection MetaModel to consider
* @param array $aClasses Flat list of classes
*
* @return string the lowest common ancestor amongst classes, null if none has been found
* @throws Exception
*/
public static function GetLowestCommonAncestor(ModelReflection $oModelReflection, $aClasses)
{
$sAncestor = null;
foreach($aClasses as $sClass)
{
if (is_null($sAncestor))
{
foreach ($aClasses as $sClass) {
if (is_null($sAncestor)) {
// first loop
$sAncestor = $sClass;
}
elseif ($oModelReflection->GetRootClass($sClass) != $oModelReflection->GetRootClass($sAncestor))
{
} elseif ($oModelReflection->GetRootClass($sClass) != $oModelReflection->GetRootClass($sAncestor)) {
$sAncestor = null;
break;
}
else
{
} else {
$sAncestor = self::LowestCommonAncestor($oModelReflection, $sAncestor, $sClass);
}
}
return $sAncestor;
}
@@ -766,37 +722,32 @@ class OqlUnionQuery extends OqlQuery
*/
protected static function LowestCommonAncestor(ModelReflection $oModelReflection, $sClassA, $sClassB)
{
if ($sClassA == $sClassB)
{
if ($sClassA == $sClassB) {
$sRet = $sClassA;
}
elseif (in_array($sClassA, $oModelReflection->EnumChildClasses($sClassB)))
{
} elseif (in_array($sClassA, $oModelReflection->EnumChildClasses($sClassB))) {
$sRet = $sClassB;
}
elseif (in_array($sClassB, $oModelReflection->EnumChildClasses($sClassA)))
{
} elseif (in_array($sClassB, $oModelReflection->EnumChildClasses($sClassA))) {
$sRet = $sClassA;
}
else
{
} else {
// Recurse
$sRet = self::LowestCommonAncestor($oModelReflection, $sClassA, $oModelReflection->GetParentClass($sClassB));
}
return $sRet;
}
/**
* Make the relevant DBSearch instance (FromOQL)
*/
*/
public function ToDBSearch($sQuery)
{
$aSearches = array();
foreach ($this->aQueries as $oQuery)
{
foreach ($this->aQueries as $oQuery) {
$aSearches[] = $oQuery->ToDBSearch($sQuery);
}
$oSearch = new DBUnionSearch($aSearches);
return $oSearch;
}
}

View File

@@ -415,12 +415,7 @@ abstract class User extends cmdbAbstractObject
$this->m_aCheckIssues[] = Dict::S('Class:User/Error:CurrentProfilesHaveInsufficientRights');
}
$oAddon->ResetCache();
if (is_null($aCurrentProfiles)) {
Session::IsSet('profile_list');
} else {
Session::Set('profile_list', $aCurrentProfiles);
}
Session::Set('profile_list', $aCurrentProfiles);
}
// Prevent an administrator to remove their own admin profile
if (UserRights::IsAdministrator($this)) {

View File

@@ -4,7 +4,7 @@
*/
$ibo-field--spacing-top--with-same-block: $ibo-spacing-500 !default;
.ibo-field + .ibo-field {
.ibo-field + .ibo-field:not(:empty) {
margin-top: $ibo-field--spacing-top--with-same-block;
}

View File

@@ -6,4 +6,95 @@
.ibo-prop-header {
@extend %ibo-font-size-150;
padding-bottom: 14px;
}
}
.help-text{
padding: 1px 5px;
background-color: #d7e3f8;
border: 1px solid #c6e7f5;
border-radius: 5px;
margin: 5px 0;
font-size: 0.9em;
}
.form-error ul{
padding: 1px 5px;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 5px;
margin: 5px 0;
font-size: 0.9em;
}
.subform{
background-color: #efefef;
border-radius: 5px;
padding: 10px;
}
.form-buttons{
margin: 20px 0;
}
.form select{
padding: 0;
overflow-y: auto;
}
.form select option{
height: 30px;
display: flex;
align-items: center;
}
.turbo-refreshing{
opacity: .5;
}
.ibo-field legend{
margin-top: 24px;
}
collection-entry-element {
margin-top: 8px;
display: block;
padding: 10px 10px;
background-color: #f5f5f5;
border-radius: 5px;
}
.ts-control{
height: auto;
min-height: 30px;
}
.ibo-form-actions > .ibo-button > span{
margin-right: 5px;
}
.ibo-form textarea{
resize: vertical;
}
.ibo-form-compact{
.ibo-field{
display: flex;
flex-direction: column;
gap: 4px;
label{
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
max-width: unset;
padding-right: 0;
}
}
}

View File

@@ -19,7 +19,10 @@ $ibo-dashlet-blocker--height: 100% !default;
.ibo-dashlet {
position: relative;
width: calc(#{$ibo-dashlet--width} - #{$ibo-dashlet--elements-spacing-x});
margin: calc(#{$ibo-dashlet--elements-spacing-y} / 2) calc(#{$ibo-dashlet--elements-spacing-x} / 2);
//margin: calc(#{$ibo-dashlet--elements-spacing-y} / 2) calc(#{$ibo-dashlet--elements-spacing-x} / 2);
height: 100% !important;
width: 100% !important;
&.dashlet-selected {
position: relative;
@@ -38,4 +41,21 @@ $ibo-dashlet-blocker--height: 100% !default;
width: $ibo-dashlet-blocker--width;
height: $ibo-dashlet-blocker--height;
cursor: not-allowed;
}
.ibo-dashlet--actions {
position: absolute;
z-index: 1000;
top: 0px;
right: 0px;
display: none;
padding: 4px;
border-radius: 4px;
background-color: $ibo-color-white-100;
@extend %ibo-elevation-100;
}
ibo-dashlet[data-edit-mode="edit"] {
z-index: 3;
}

View File

@@ -54,3 +54,31 @@ $ibo-input-select-icon--menu--icon--margin-right: 10px !default;
}
}
}
.ts-control > .ibo-input-select-icon--menu--item{
display: flex;
column-gap: 5px;
align-items: center;
padding: 5px 0;
> img{
width: 20px;
}
&:hover{
background: transparent;
}
}
.ts-dropdown > .ts-dropdown-content > .ibo-input-select-icon--menu--item{
display: flex;
column-gap: 5px;
> img{
width: 32px;
}
}

View File

@@ -15,3 +15,4 @@
@import "wizard-container/wizard-container";
@import "object/all";
@import "activity-panel/all";
@import "dashlet-panel/all";

View File

@@ -175,3 +175,73 @@ input:checked + .ibo-dashboard--slider:before {
input:checked + .ibo-dashboard--slider:after {
content: $ibo-dashboard--slider--before--content;
}
// TODO 3.3 Cleanup variables
// TODO 3.3 Move to vendor what's from gridstack
.grid-stack {
display: block;
}
.ibo-dashboard[data-edit-mode="edit"] .grid-stack{
background-size: calc(100% / 12) var(--gs-cell-height);
background-color: $ibo-color-white-100;
background-image: linear-gradient(to right, $ibo-color-white-200 8px, transparent 8px), linear-gradient(to bottom, $ibo-color-white-200 8px, transparent 8px);
--gs-item-margin-top: 8px;
--gs-item-margin-bottom: 0;
--gs-item-margin-right: 0;
--gs-item-margin-left: 8px;
}
ibo-dashboard[data-edit-mode="view"] {
.ibo-dashboard--form {
display: none;
}
}
.ibo-dashboard--form {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
height: 55px;
background-color: $ibo-color-blue-200;
margin: -16px -36px 24px -36px;
padding: 0 36px;
}
.ibo-dashboard--form--inputs {
display: flex;
flex-direction: row;
align-items: center;
gap: 12px;
@extend %common-font-ral-med-250;
}
.ibo-dashboard[data-edit-mode="edit"] ibo-dashlet:not([data-edit-mode="edit"]):hover .ibo-dashlet--actions {
display: block;
}
.ibo-dashboard[data-edit-mode="error"] .grid-stack{
background-image: url($approot-relative + '/images/alpha-fatal-error.gif');
}
// Our edit mode dashboard already has its own header, so we hide the standard one
#ibo-page-header:has(+ ibo-dashboard[data-edit-mode="edit"]) {
display: none;
}
.ibo-dashboard[data-edit-mode="edit"] .ibo-dashboard--grid:has(ibo-dashboard-grid-slot > ibo-dashlet[data-edit-mode="edit"]) .ibo-dashboard--grid--backdrop {
position: absolute;
height: calc(100% + 24px);
// 36px is $ibo-page-container--elements-padding-x, handle variable resolution
width: calc(100% + 36px + 36px);
margin: -24px -#{36px} 0 -#{36px};
background-color: $ibo-color-grey-400;
z-index: 2;
opacity: 60%;
}

View File

@@ -0,0 +1,2 @@
@import "dashlet-entry";
@import "dashlet-panel";

View File

@@ -0,0 +1,51 @@
// TODO 3.3 Cleanup variables
.ibo-dashlet-entry {
display: flex;
flex-direction: row;
gap: 10px;
border: 1px solid $ibo-color-grey-300;
border-radius: 5px;
padding: 12px;
background-color: $ibo-color-grey-100;
cursor: pointer;
text-align: left;
&:hover {
background-color: $ibo-color-grey-200;
border-color: $ibo-color-grey-400;
}
&:active {
background-color: $ibo-color-grey-50;
border-color: $ibo-color-grey-500;
}
}
.ibo-dashlet-entry--icon {
flex-shrink: 0;
height: 36px;
width: 36px;
}
.ibo-dashlet-entry--content {
display: flex;
flex-direction: column;
justify-content: center;
overflow-x: hidden;
gap: 4px;
}
.ibo-dashlet-entry--title {
font-size: 14px;
font-weight: 600;
color: $ibo-color-grey-900;
}
.ibo-dashlet-entry--description {
font-size: 12px;
color: $ibo-color-grey-700;
}

View File

@@ -0,0 +1,66 @@
// TODO 3.3 Cleanup variables
.ibo-dashlet-panel {
height: 100%;
display: flex;
flex-direction: column;
width: 326px;
background-color: $ibo-color-white-100;
}
.ibo-dashlet-panel--title {
display: flex;
flex-direction: column;
justify-content: center;
height: 55px;
background-color: $ibo-color-white-200;
padding: 0 16px;
flex-grow: 0;
@extend %common-font-ral-med-300;
}
.ibo-dashlet-panel--entries, .ibo-dashlet-panel--form-container {
flex-grow: 1;
display: flex;
flex-direction: column;
overflow: auto;
padding: 16px;
gap: 12px;
&.ibo-is-hidden {
display: none;
}
}
.ibo-center-container:has(ibo-dashboard[data-edit-mode="view"]) .ibo-dashlet-panel{
display: none;
}
.ibo-dashlet-panel--form-container turbo-frame {
height: 100%;
}
.ibo-dashlet-panel--form-container .ibo-form {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
> .form {
overflow: auto;
margin-bottom: 16px;
}
}
.ibo-dashlet-panel--form-container--buttons {
display: flex;
flex-direction: row !important;
justify-content: end;
align-items: center;
margin: 0 -16px -16px -16px;
padding: 0 16px;
min-height: 60px;
background-color: $ibo-color-grey-50;
border-top: solid 1px $ibo-color-grey-400;
}

View File

@@ -0,0 +1,3 @@
@import "../../../node_modules/tom-select/dist/scss/tom-select.scss";
$select-color-item-active-border: $ibo-input--focus--border-color;

File diff suppressed because one or more lines are too long

View File

@@ -523,12 +523,7 @@ body {
}
.ibo-setup-summary-title {
font-size: $ibo-font-size-150;
color: black;
}
.ibo-setup-summary-title:visited {
color: black;
font-size: $ibo-font-size-150;
}
#ibo-setup-licenses--components-list {
@@ -610,7 +605,6 @@ body {
color:#a00000;
}
.setup-extension-tag {
display: inline-flex;
background-color: grey;
border-radius: 8px;
padding-left: 3px;
@@ -687,6 +681,9 @@ body {
overflow: auto;
text-align: center;
}
#installation_progress {
display: none;
}
#fresh_content{
border: 0;
min-height: 300px;

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="Combodo\iTop\DataFeatureRemoval\" />
<sourceFolder url="file://$MODULE_DIR$/src/NoNamespace" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/combodo-data-feature-removal.iml" filepath="$PROJECT_DIR$/.idea/combodo-data-feature-removal.iml" />
</modules>
</component>
</project>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpIncludePathManager">
<include_path>
<path value="$PROJECT_DIR$/vendor/composer" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
<option name="suggestChangeDefaultLanguageLevel" value="false" />
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="0556f797-a2a3-4617-8eb0-c7985d4d9530" name="Changes" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ComposerSettings" synchronizationState="SYNCHRONIZE">
<pharConfigPath>$PROJECT_DIR$/composer.json</pharConfigPath>
<execution />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="PhpWorkspaceProjectConfiguration" interpreter_name="PHP 7.2">
<include_path>
<path value="$PROJECT_DIR$/vendor/composer" />
</include_path>
</component>
<component name="ProjectColorInfo">{
&quot;customColor&quot;: &quot;&quot;,
&quot;associatedIndex&quot;: 1
}</component>
<component name="ProjectId" id="38XKfHC46lRTrwwYc7IxUdzfXo1" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="autoscrollFromSource" value="true" />
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"last_opened_file_path": "/home/combodo/workspaceHUB/HubInstallation",
"node.js.detected.package.eslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"nodejs_package_manager_path": "npm"
}
}]]></component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
</project>

View File

@@ -1,9 +0,0 @@
/*
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/*
* CSS of the template page
*/

View File

@@ -1,9 +0,0 @@
/*
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/*
* Javascript file loaded in template page
*/

View File

@@ -1,17 +0,0 @@
{
"config": {
"classmap-authoritative": true
},
"autoload": {
"psr-4": {
"Combodo\\iTop\\DataFeatureRemoval\\": "src",
"": "src/NoNamespace"
}
},
"name": "combodo/combodo-data-feature-removal",
"type": "itop-extension",
"description": "iTop Data Feature Removal",
"require": {
"composer-runtime-api": "^2.0"
}
}

View File

@@ -1,163 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
<classes>
<class id="DataFeatureRemoverExtension" _delta="define">
<properties>
<category>grant_by_profile</category>
<db_table>data_feature_removal_extension</db_table>
<naming>
<attributes/>
</naming>
<reconciliation>
<attributes>
<attribute id="extension_code"/>
</attributes>
</reconciliation>
<uniqueness_rules/>
</properties>
<fields>
<field id="extension_code" xsi:type="AttributeString">
<sql>extension_code</sql>
<is_null_allowed>false</is_null_allowed>
<tracking_level>all</tracking_level>
</field>
<field id="label" xsi:type="AttributeString">
<sql>label</sql>
<is_null_allowed>false</is_null_allowed>
<tracking_level>all</tracking_level>
</field>
<field id="version" xsi:type="AttributeString">
<sql>version</sql>
<is_null_allowed>false</is_null_allowed>
<tracking_level>all</tracking_level>
</field>
<field id="module_names" xsi:type="AttributeText">
<sql>module_names</sql>
<is_null_allowed>false</is_null_allowed>
<tracking_level>all</tracking_level>
</field>
<field id="status" xsi:type="AttributeString">
<sql>status</sql>
<default_value>none</default_value>
<is_null_allowed>true</is_null_allowed>
<tracking_level>all</tracking_level>
</field>
</fields>
<presentation>
<list>
<items>
<item id="extension_code">
<rank>10</rank>
</item>
<item id="status">
<rank>20</rank>
</item>
</items>
</list>
<search>
<item id="extension_code">
<rank>10</rank>
</item>
<item id="status">
<rank>20</rank>
</item>
</search>
<details>
<item id="extension_code">
<rank>10</rank>
</item>
<item id="status">
<rank>20</rank>
</item>
</details>
</presentation>
<methods/>
</class>
<class id="DataFeatureRemoverAuditRule" _delta="define">
<properties>
<category>grant_by_profile</category>
<db_table>data_feature_removal_auditrule</db_table>
<naming>
<attributes/>
</naming>
<reconciliation>
<attributes>
<attribute id="rule_name"/>
<attribute id="extension_code"/>
<attribute id="class_name"/>
</attributes>
</reconciliation>
<uniqueness_rules/>
</properties>
<fields>
<field id="rule_name" xsi:type="AttributeString">
<sql>rule_name</sql>
<is_null_allowed>false</is_null_allowed>
<tracking_level>all</tracking_level>
</field>
<field id="extension_code" xsi:type="AttributeString">
<sql>extension_code</sql>
<is_null_allowed>false</is_null_allowed>
<tracking_level>all</tracking_level>
</field>
<field id="class_name" xsi:type="AttributeText">
<sql>class_name</sql>
<default_value>none</default_value>
<is_null_allowed>true</is_null_allowed>
<tracking_level>all</tracking_level>
</field>
<field id="count" xsi:type="AttributeInteger">
<sql>count</sql>
<default_value>0</default_value>
<tracking_level>all</tracking_level>
</field>
</fields>
<presentation>
<list>
<items>
<item id="rule_name">
<rank>10</rank>
</item>
<item id="extension_code">
<rank>20</rank>
</item>
<item id="class_name">
<rank>30</rank>
</item>
</items>
</list>
<search>
<item id="rule_name">
<rank>10</rank>
</item>
<item id="extension_code">
<rank>20</rank>
</item>
<item id="class_name">
<rank>30</rank>
</item>
</search>
<details>
<item id="rule_name">
<rank>10</rank>
</item>
<item id="extension_code">
<rank>20</rank>
</item>
<item id="class_name">
<rank>30</rank>
</item>
</details>
</presentation>
<methods/>
</class>
</classes>
<menus>
<menu id="DataFeatureRemovalMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>30</rank>
<parent>SystemTools</parent>
<url>$pages/exec.php?exec_module=combodo-data-feature-removal&amp;exec_page=index.php&amp;c[menu]=DataFeatureRemovalMenu</url>
<enable_admin_only>1</enable_admin_only>
</menu>
</menus>
</itop_design>

View File

@@ -1,41 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Localized data
*/
Dict::Add('EN US', 'English', 'English', [
'Menu:DataFeatureRemovalMenu' => 'Features Removal',
'combodo-data-feature-removal/Operation:Main/Title' => 'Features Removal',
'DataFeatureRemoval:Main:Title' => 'Features Removal',
'DataFeatureRemoval:Main:SubTitle' => 'Prepare features you want to enable/disable in a future setup',
'DataFeatureRemoval:Failure:Title' => 'Feature dry removal errors',
'DataFeatureRemoval:Helper:Title' => 'This utilitary allows you to enable or disable features that are installed in your iTop.',
'DataFeatureRemoval:Helper:Desc1' => 'It will prepare the setup step that proceeds to feature enabling or disabling.',
'DataFeatureRemoval:Helper:Desc2' => 'You will need to analyze if there are any data or dependency preventing you from enabling/disabling a feature.',
'DataFeatureRemoval:Features:Title' => 'Features',
'DataFeatureRemoval:Analysis:Title' => 'Analysis result',
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s element(s) to clean before continuing',
'DataFeatureRemoval:Table:Analysis:ClassName' => 'Element to remove',
'DataFeatureRemoval:Table:Analysis:RemovalType' => 'Type of element',
'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Feature name',
'DataFeatureRemoval:Table:Analysis:Occurence' => 'Occurence',
'UI:Button:Analyze' => 'Analyze',
'UI:Button:ModifyChoices' => 'Modify Choices',
'UI:Button:AnalyzeAndSetup' => 'Analyze and go to setup',
'UI:Action:ForceUninstall' => 'Force uninstall',
'UI:Action:MoreInfo' => 'More information',
'DataFeatureRemoval:Table:Analysis:RemovalType:FINAL_CLASS' => 'Final class',
]);

View File

@@ -1,40 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Localized data
*/
Dict::Add('FR FR', 'French', 'Français', [
'Menu:DataFeatureRemovalMenu' => 'Features Removal',
'combodo-data-feature-removal/Operation:Main/Title' => 'Features Removal',
'DataFeatureRemoval:Main:Title' => 'Features Removal',
'DataFeatureRemoval:Main:SubTitle' => 'Prepare features you want to enable/disable in a future setup',
'DataFeatureRemoval:Failure:Title' => 'Feature dry removal errors',
'DataFeatureRemoval:Helper:Title' => 'This utilitary allows you to enable or disable features that are installed in your iTop.',
'DataFeatureRemoval:Helper:Desc1' => 'It will prepare the setup step that proceeds to feature enabling or disabling.',
'DataFeatureRemoval:Helper:Desc2' => 'You will need to analyze if there are any data or dependency preventing you from enabling/disabling a feature.',
'DataFeatureRemoval:Features:Title' => 'Features',
'DataFeatureRemoval:Analysis:Title' => 'Analysis result',
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s element(s) to clean before continuing',
'DataFeatureRemoval:Table:Analysis:ClassName' => 'Element to remove',
'DataFeatureRemoval:Table:Analysis:RemovalType' => 'Type of element',
'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Feature name',
'DataFeatureRemoval:Table:Analysis:Occurence' => 'Occurence',
'UI:Button:Analyze' => 'Analyze',
'UI:Button:ModifyChoices' => 'Modify Choices',
'UI:Button:AnalyzeAndSetup' => 'Analyze and go to setup',
'UI:Action:ForceUninstall' => 'Force uninstall',
'UI:Action:MoreInfo' => 'More information',
'DataFeatureRemoval:Table:Analysis:RemovalType:FINAL_CLASS' => 'Final class',
]);

View File

@@ -1,20 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\DataFeatureRemoval;
use Combodo\iTop\DataFeatureRemoval\Controller\DataFeatureRemovalController;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalLog;
require_once(APPROOT.'application/startup.inc.php');
DataFeatureRemovalLog::Enable();
$oController = new DataFeatureRemovalController(MODULESROOT.DataFeatureRemovalHelper::MODULE_NAME.'/templates', DataFeatureRemovalHelper::MODULE_NAME);
$oController->SetDefaultOperation('Main');
$oController->HandleOperation();

View File

@@ -1,16 +0,0 @@
<?php
// PHP Data Model definition file
// WARNING - WARNING - WARNING
// DO NOT EDIT THIS FILE (unless you know what you are doing)
//
// If you provide a datamodel.xxxx.xml file with your module,
// this file WILL BE overwritten by the compilation of the
// module (during the setup) if the datamodel.xxxx.xml file
// contains the definition of new classes or menus.
//
// The recommended way to define new classes (for iTop 2.0 and later) is via the XML definition.
// This file remains in the module's template only for the cases where there is:
// - either no new class or menu defined in the XML file
// - or no XML file at all supplied by the module

View File

@@ -1,54 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
//
// iTop module definition file
//
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'combodo-data-feature-removal/3.3.0',
[
// Identification
//
'label' => 'iTop Data Feature Removal',
'category' => 'business',
// Setup
//
'dependencies' => [
],
'mandatory' => true,
'visible' => false,
// Components
//
'datamodel' => [
'vendor/autoload.php',
'model.combodo-data-feature-removal.php', // Contains the PHP code generated by the "compilation" of datamodel.combodo-data-feature-removal.xml
],
'webservice' => [],
'data.struct' => [
// add your 'structure' definition XML files here,
],
'data.sample' => [
// add your sample data XML files here,
],
// Documentation
//
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
'doc.more_information' => '', // hyperlink to more information, if any
// Default settings
//
'settings' => [
// Module specific settings go here, if any
],
]
);

View File

@@ -1,189 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\DataFeatureRemoval\Controller;
require_once APPROOT.'setup/feature_removal/SetupAudit.php';
require_once APPROOT.'setup/feature_removal/DryRemovalRuntimeEnvironment.php';
use Combodo\iTop\Application\TwigBase\Controller\Controller;
use Combodo\iTop\AuthentToken\Helper\TokenAuthLog;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
use Combodo\iTop\DataFeatureRemoval\Model\DataFeatureRemoverAuditRuleService;
use Combodo\iTop\DataFeatureRemoval\Model\DataFeatureRemoverExtensionService;
use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment;
use Combodo\iTop\Setup\FeatureRemoval\SetupAudit;
use Dict;
use Exception;
use MetaModel;
use utils;
class DataFeatureRemovalController extends Controller
{
private array $aSelectedExtensionsForCheck = [];
public function OperationMain($sErrorMessage = null)
{
$aParams = [];
$this->AddLinkedStylesheet(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/css/DataFeatureRemoval.css');
$this->AddLinkedScript(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/js/DataFeatureRemoval.js');
$aParams['sTransactionId'] = utils::GetNewTransactionId();
$this->AddFeatureParams($aParams);
$this->AddAnalyzeParams($aParams);
$aParams['DataFeatureRemovalErrorMessage'] = $sErrorMessage;
$this->DisplayPage($aParams);
}
public function AddFeatureParams(array &$aParams)
{
$aParams['aExtensions'] = $this->GetExtensionsTable();
$aParams['sModule'] = DataFeatureRemovalHelper::MODULE_NAME;
}
public function AddAnalyzeParams(array &$aParams)
{
$iTotalCount = 0;
$aData = [];
$aColumns = [];
foreach (DataFeatureRemoverAuditRuleService::GetInstance()->ReadCheckRules() as $oRule) {
$sContent = $oRule->Get('class_name');
$sModuleName = MetaModel::GetModuleName($sContent);
$aExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetIncludingExtensions($sModuleName);
$sExtensions = implode(' ', $aExtensions);
$sTypeName = $oRule->Get('rule_name');
$sTypeDesc = \Dict::S("DataFeatureRemoval:Table:Analysis:RemovalType:$sTypeName");
$iCount = $oRule->Get('count');
$iTotalCount += $iCount;
$aColumns = ['ClassName', 'RemovalType','FeatureName','Occurence'];
$aData[] = [
<<<HTML
<label>$sContent</label>
HTML,
<<<HTML
<label>$sTypeDesc</label>
HTML,
<<<HTML
<label title="$sModuleName">$sExtensions</label>
HTML,
<<<HTML
<label>$iCount</label>
HTML,
];
}
$aParams['aCheckRules'] = $this->GetTableData('Analysis', $aColumns, $aData);
$aParams['rule_count'] = $iTotalCount;
}
public function OperationAnalyze()
{
$aSelectedExtensionsFromUI = utils::ReadPostedParam('aExtensions', []);
$this->aSelectedExtensionsForCheck = [];
foreach ($aSelectedExtensionsFromUI as $sCode => $aData) {
$sValue = $aData['enable'] ?? 'off';
if (($sValue) === 'on') {
$this->aSelectedExtensionsForCheck[] = $sCode;
}
}
$this->m_sOperation = 'Main';
try {
$this->Analyze();
$this->OperationMain();
} catch (Exception $e) {
\IssueLog::Error(__METHOD__, null, ['stack' => $e->getTraceAsString(), 'exception' => $e->getMessage()]);
$this->OperationMain($e->getMessage());
}
}
private function GetExtensionsTable(): array
{
$aExtensions = [];
$aColumns = ['', 'Version', 'Name', 'Code'];
$this->aSelectedExtensionsForCheck = DataFeatureRemoverExtensionService::GetInstance()->ReadAuditedExtensions();
foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) {
/** @var \iTopExtension $oExtension */
$sChecked = "checked";
$sDisabledHtml = '';
if ($oExtension->bRemovedFromDisk) {
$sDisabledHtml = 'disabled=""';
} elseif (! array_key_exists($sCode, $this->aSelectedExtensionsForCheck)) {
$sChecked = "";
}
$sLabel = $oExtension->sLabel;
$sVersion = $oExtension->sVersion;
$sIdEnable = "aExtensions[$sCode][enable]";
$aExtensions[] = [
<<<HTML
<input type="checkbox" $sDisabledHtml class="extension_check" $sChecked id="$sIdEnable" name="$sIdEnable"/>
HTML,
<<<HTML
<label>$sVersion</label>
HTML,
<<<HTML
<label for="$sIdEnable">$sLabel</label>
HTML,
<<<HTML
<label for="$sIdEnable">$sCode</label>
HTML,
];
}
return $this->GetTableData('Extensions', $aColumns, $aExtensions);
}
public function GetTableData(string $sTableName, array $aColumns, array $aData): array
{
if (empty($aData)) {
return [
'Type' => 'Table',
'Columns' => [['label' => '']],
'Data' => [[ Dict::S('DbCleaner:Table:Empty')]],
];
}
$aNewColumns = [];
foreach ($aColumns as $sColumn) {
$aNewColumns[] = ['label' => Dict::S("DataFeatureRemoval:Table:$sTableName:$sColumn", $sColumn)];
}
$aColumns = $aNewColumns;
return [
'Type' => 'Table',
'Columns' => $aColumns,
'Data' => $aData,
];
}
private function Analyze()
{
DataFeatureRemoverExtensionService::GetInstance()->SaveExtensions($this->aSelectedExtensionsForCheck);
$sSourceEnvt = \MetaModel::GetEnvironment();
$oDryRemovalRuntimeEnvironment = new DryRemovalRuntimeEnvironment();
$oDryRemovalRuntimeEnvironment->Prepare($sSourceEnvt, $this->aSelectedExtensionsForCheck);
$oDryRemovalRuntimeEnvironment->CompileFrom($sSourceEnvt);
$oSetupAudit = new SetupAudit($sSourceEnvt, DryRemovalRuntimeEnvironment::DRY_REMOVAL_AUDIT_ENV);
$this->Save($oSetupAudit->GetIssues());
}
private function Save(array $aGetRemovedClasses)
{
\IssueLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]);
DataFeatureRemoverAuditRuleService::GetInstance()->SaveChecks($aGetRemovedClasses);
}
}

View File

@@ -1,30 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\DataFeatureRemoval\Helper;
use Exception;
use Throwable;
class DataFeatureRemovalException extends Exception
{
public function __construct(string $message = '', int $code = 0, ?Throwable $previous = null, array $aContext = [])
{
if (!is_null($previous)) {
$sStack = $previous->getTraceAsString();
$sError = $previous->getMessage();
} else {
$sStack = $this->getTraceAsString();
$sError = '';
}
$aContext['error'] = $sError;
$aContext['stack'] = $sStack;
DataFeatureRemovalLog::Error($message, null, $aContext);
parent::__construct($message, $code, $previous);
}
}

View File

@@ -1,13 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\DataFeatureRemoval\Helper;
class DataFeatureRemovalHelper
{
public const MODULE_NAME = 'combodo-data-feature-removal';
}

View File

@@ -1,25 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\DataFeatureRemoval\Helper;
use LogAPI;
class DataFeatureRemovalLog extends LogAPI
{
public const CHANNEL_DEFAULT = 'DataFeatureRemoval';
protected static $m_oFileLog = null;
public static function Enable($sTargetFile = null)
{
if (empty($sTargetFile)) {
$sTargetFile = APPROOT.'log/error.log';
}
parent::Enable($sTargetFile);
}
}

View File

@@ -1,70 +0,0 @@
<?php
namespace Combodo\iTop\DataFeatureRemoval\Model;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
use DataFeatureRemoverAuditRule;
use DBObjectSearch;
use DBObjectSet;
use Exception;
class DataFeatureRemoverAuditRuleService
{
private static DataFeatureRemoverAuditRuleService $oInstance;
protected function __construct()
{
}
final public static function GetInstance(): DataFeatureRemoverAuditRuleService
{
if (!isset(self::$oInstance)) {
self::$oInstance = new DataFeatureRemoverAuditRuleService();
}
return self::$oInstance;
}
final public static function SetInstance(?DataFeatureRemoverAuditRuleService $oInstance): void
{
self::$oInstance = $oInstance;
}
public function SaveChecks(array $aGetRemovedClasses)
{
$oSearch = DBObjectSearch::FromOQL('SELECT DataFeatureRemoverAuditRule', []);
$oSearch->AllowAllData();
$oSet = new DBObjectSet($oSearch);
while (null != ($oObj = $oSet->Fetch())) {
$oObj->DBDelete();
}
foreach ($aGetRemovedClasses as $sClass => $iCount) {
$oObj = new DataFeatureRemoverAuditRule();
$oObj->Set('rule_name', 'FINAL_CLASS');
$oObj->Set('extension_code', $sClass);
$oObj->Set('class_name', $sClass);
$oObj->Set('count', $iCount);
$oObj->DBWrite();
}
}
public function ReadCheckRules(): array
{
try {
$oSearch = DBObjectSearch::FromOQL('SELECT DataFeatureRemoverAuditRule', []);
$oSearch->AllowAllData();
$oSet = new DBObjectSet($oSearch);
$aRes = [];
while (null != ($oObj = $oSet->Fetch())) {
$aRes[] = $oObj;
}
return $aRes;
} catch (Exception $e) {
throw new DataFeatureRemovalException(__FUNCTION__.' failed', 0, $e);
}
}
}

View File

@@ -1,122 +0,0 @@
<?php
namespace Combodo\iTop\DataFeatureRemoval\Model;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
use DataFeatureRemoverExtension;
use DBObjectSearch;
use DBObjectSet;
use Exception;
use iTopExtension;
use iTopExtensionsMap;
use MetaModel;
class DataFeatureRemoverExtensionService
{
private static DataFeatureRemoverExtensionService $oInstance;
protected function __construct()
{
}
final public static function GetInstance(): DataFeatureRemoverExtensionService
{
if (!isset(self::$oInstance)) {
self::$oInstance = new DataFeatureRemoverExtensionService();
}
return self::$oInstance;
}
final public static function SetInstance(?DataFeatureRemoverExtensionService $oInstance): void
{
self::$oInstance = $oInstance;
}
public function SaveExtensions(array $aSelectedExtensionsForCheck)
{
$this->ReadItopExtensions();
$oSearch = DBObjectSearch::FromOQL('SELECT DataFeatureRemoverExtension', []);
$oSearch->AllowAllData();
$oSet = new DBObjectSet($oSearch);
while (null != ($oObj = $oSet->Fetch())) {
$oObj->DBDelete();
}
foreach ($aSelectedExtensionsForCheck as $i => $sCode) {
$oObj = new DataFeatureRemoverExtension();
$oObj->Set('extension_code', $sCode);
/** @var iTopExtension $oExtension */
$oExtension = $this->aItopExtensions[$sCode];
$oObj->Set('module_names', json_encode($oExtension->aModules));
$oObj->Set('label', $oExtension->sLabel);
$oObj->Set('version', $oExtension->sVersion);
$oObj->DBWrite();
}
}
private array $aSelectedExtensions = [];
private array $aItopExtensions = [];
private array $aIncludingExtensionsByModuleName = [];
public function ReadAuditedExtensions(): array
{
if (count($this->aSelectedExtensions) == 0) {
try {
$oSearch = DBObjectSearch::FromOQL('SELECT DataFeatureRemoverExtension', []);
$oSearch->AllowAllData();
$oSet = new DBObjectSet($oSearch);
while (null != ($oObj = $oSet->Fetch())) {
$sCode = $oObj->Get('extension_code');
$sLabel = $oObj->Get('label');
$sVersion = $oObj->Get('version');
$sModuleNames = $oObj->Get('module_names');
$aModuleNames = json_decode($sModuleNames, true);
if (is_array($aModuleNames) && count($aModuleNames) > 0) {
foreach ($aModuleNames as $sModuleName) {
$aExtensions = $this->aIncludingExtensionsByModuleName[$sModuleName] ?? [];
$aExtensions[] = "$sLabel / $sVersion";
$this->aIncludingExtensionsByModuleName[$sModuleName] = $aExtensions;
}
}
$this->aSelectedExtensions[$sCode] = $oObj;
}
} catch (Exception $e) {
throw new DataFeatureRemovalException(__FUNCTION__.' failed', 0, $e);
}
}
\IssueLog::Debug(__METHOD__, null, ['aSelectedExtensionsForCheck' => $this->aSelectedExtensions]);
\IssueLog::Debug(__METHOD__, null, ['aIncludingExtensionsByModuleName' => $this->aIncludingExtensionsByModuleName]);
return $this->aSelectedExtensions;
}
public function GetIncludingExtensions(string $sModuleName): array
{
$this->ReadAuditedExtensions();
return $this->aIncludingExtensionsByModuleName[$sModuleName] ?? [];
}
/**
* @return iTopExtension[]
*/
public function ReadItopExtensions(): array
{
if (count($this->aItopExtensions) == 0) {
$oExtensionsMap = new iTopExtensionsMap();
$oExtensionsMap->LoadInstalledExtensionsFromDatabase(MetaModel::GetConfig());
$this->aItopExtensions = $oExtensionsMap->GetAllExtensionsToDisplayInSetup(true);
uasort($this->aItopExtensions, function (iTopExtension $oiTopExtension1, iTopExtension $oiTopExtension2) {
return strcmp($oiTopExtension1->sLabel, $oiTopExtension2->sLabel);
});
}
return $this->aItopExtensions;
}
}

View File

@@ -1,8 +0,0 @@
{# @copyright Copyright (C) 2010-2024 Combodo SAS #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
{% UIForm Standard {} %}
{% UIPanel Neutral { sTitle:'DataFeatureRemoval:Analysis:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:Analysis:SubTitle'|dict_format(rule_count) } %}
{% UIDataTable ForForm { sRef:'aCheckRules', aColumns:aCheckRules.Columns, aData:aCheckRules.Data} %}{% EndUIDataTable %}
{% EndUIPanel %}
{% EndUIForm %}

View File

@@ -1,18 +0,0 @@
{# @copyright Copyright (C) 2010-2024 Combodo SAS #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
{% UIForm Standard {} %}
{% UIInput ForHidden {sName:'operation', sValue:'Analyze'} %}
{% UIInput ForHidden {sName:'transaction_id', sValue:sTransactionId} %}
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Features:Title'|dict_s} %}
{% UIDataTable ForForm { sRef:'aExtensions', aColumns:aExtensions.Columns, aData:aExtensions.Data} %}{% EndUIDataTable %}
{% EndUIFieldSet %}
{% UIToolbar ForButton {} %}
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Analyze'|dict_s, sName:'btn_apply', sId:'btn_apply', bIsSubmit:true} %}
{% EndUIToolbar %}
{% EndUIForm %}

View File

@@ -1,28 +0,0 @@
{# @copyright Copyright (C) 2010-2025 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
{# Usable variables: #}
{# * sTitle => page title #}
{# * sMessage => success message #}
{# * sError => error message #}
{# DataFeatureRemoval #}
{% UIPanel Neutral { sTitle:'DataFeatureRemoval:Main:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:Main:SubTitle'|dict_s } %}
{% UIAlert ForInformation { sTitle:'DataFeatureRemoval:Helper:Title'|dict_s } %}
{{ 'DataFeatureRemoval:Helper:Desc1'|dict_s }}<BR>
{{ 'DataFeatureRemoval:Helper:Desc2'|dict_s }}
{% EndUIAlert %}
{% if null != DataFeatureRemovalErrorMessage %}
<div id="feature_removal_error_msg_div" style="display:block">
{% UIAlert ForFailure { sTitle:'DataFeatureRemoval:Failure:Title'|dict_s, sId: 'feature_removal_error_msg', sContent:DataFeatureRemovalErrorMessage } %}
{% EndUIAlert %}
</div>
{% endif %}
{% include 'FeaturesTab.html.twig' %}
{% include 'ExtensionRemovalDataTab.html.twig' %}
{% EndUIPanel %}

View File

@@ -1,9 +0,0 @@
{# @copyright Copyright (C) 2010-2024 Combodo SAS #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
$(document).on('click', '#checkAllExtensions', function() {
var bChecked = this.checked;
$('.extension_check').each( function() { this.checked = bChecked });
});

View File

@@ -1,2 +0,0 @@
{# @copyright Copyright (C) 2010-2024 Combodo SAS #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}

View File

@@ -1,25 +0,0 @@
<?php
// 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 ComposerAutoloaderInit4f96a7199e2c0d90e547333758b26464::getLoader();

View File

@@ -1,579 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* 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 list<string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var string|null */
private $apcuPrefix;
/**
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return list<string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* 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 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(
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
$paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
$paths
);
}
}
/**
* 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 list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
$paths
);
}
}
/**
* 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 list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* 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 list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
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;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
/**
* @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

@@ -1,17 +0,0 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Combodo\\iTop\\DataFeatureRemoval\\Controller\\DataFeatureRemovalController' => $baseDir . '/src/Controller/DataFeatureRemovalController.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => $baseDir . '/src/Helper/DataFeatureRemovalException.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => $baseDir . '/src/Helper/DataFeatureRemovalHelper.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalLog' => $baseDir . '/src/Helper/DataFeatureRemovalLog.php',
'Combodo\\iTop\\DataFeatureRemoval\\Model\\DataFeatureRemoverAuditRuleService' => $baseDir . '/src/Model/DataFeatureRemoverAuditRuleService.php',
'Combodo\\iTop\\DataFeatureRemoval\\Model\\DataFeatureRemoverExtensionService' => $baseDir . '/src/Model/DataFeatureRemoverExtensionService.php',
'Combodo\\iTop\\DataFeatureRemoval\\Service\\SetupAudit' => $baseDir . '/src/Service/SetupAudit.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

View File

@@ -1,9 +0,0 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
);

View File

@@ -1,11 +0,0 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Combodo\\iTop\\DataFeatureRemoval\\' => array($baseDir . '/src'),
'' => array($baseDir . '/src/NoNamespace'),
);

View File

@@ -1,37 +0,0 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit4f96a7199e2c0d90e547333758b26464
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit4f96a7199e2c0d90e547333758b26464', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit4f96a7199e2c0d90e547333758b26464', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit4f96a7199e2c0d90e547333758b26464::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
return $loader;
}
}

View File

@@ -1,48 +0,0 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit4f96a7199e2c0d90e547333758b26464
{
public static $prefixLengthsPsr4 = array (
'C' =>
array (
'Combodo\\iTop\\DataFeatureRemoval\\' => 32,
),
);
public static $prefixDirsPsr4 = array (
'Combodo\\iTop\\DataFeatureRemoval\\' =>
array (
0 => __DIR__ . '/../..' . '/src',
),
);
public static $fallbackDirsPsr4 = array (
0 => __DIR__ . '/../..' . '/src/NoNamespace',
);
public static $classMap = array (
'Combodo\\iTop\\DataFeatureRemoval\\Controller\\DataFeatureRemovalController' => __DIR__ . '/../..' . '/src/Controller/DataFeatureRemovalController.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalException.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalHelper.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalLog' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalLog.php',
'Combodo\\iTop\\DataFeatureRemoval\\Model\\DataFeatureRemoverAuditRuleService' => __DIR__ . '/../..' . '/src/Model/DataFeatureRemoverAuditRuleService.php',
'Combodo\\iTop\\DataFeatureRemoval\\Model\\DataFeatureRemoverExtensionService' => __DIR__ . '/../..' . '/src/Model/DataFeatureRemoverExtensionService.php',
'Combodo\\iTop\\DataFeatureRemoval\\Service\\SetupAudit' => __DIR__ . '/../..' . '/src/Service/SetupAudit.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$prefixDirsPsr4;
$loader->fallbackDirsPsr4 = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$fallbackDirsPsr4;
$loader->classMap = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$classMap;
}, null, ClassLoader::class);
}
}

View File

@@ -30,7 +30,7 @@ SetupWebPage::AddModule(
// Identification
//
'label' => 'Database maintenance tools',
'category' => 'business',
'category' => 'Application management',
// Setup
//

View File

@@ -10,7 +10,6 @@ namespace Combodo\iTop\DBTools\Service;
use CMDBSource;
use DBObjectSearch;
use DBObjectSet;
use IssueLog;
class DBToolsUtils
{

View File

@@ -28,6 +28,7 @@ class ConfigEditorController extends Controller
public function __construct()
{
parent::__construct(MODULESROOT.static::MODULE_NAME.'/templates', static::MODULE_NAME);
$this->SetDebugAllowed(false);
}
public function OperationEdit(): void

View File

@@ -30,7 +30,7 @@ SetupWebPage::AddModule(
// Identification
//
'label' => 'iTop Core Update',
'category' => 'business',
'category' => 'Application management',
// Setup
//

View File

@@ -92,7 +92,7 @@ final class CoreUpdater
$sFinalEnv = 'production';
$oRuntimeEnv = new RunTimeEnvironmentCoreUpdater($sFinalEnv, false);
$oRuntimeEnv->CheckDirectories($sFinalEnv);
$oRuntimeEnv->CompileFrom($sFinalEnv);
$oRuntimeEnv->CompileFrom('production');
$oRuntimeEnv->Rollback();
@@ -155,13 +155,21 @@ final class CoreUpdater
APPROOT.'extensions',
];
$aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $aDirsToScanForModules);
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'BeforeDatabaseCreation');
$aSelectedModules = [];
foreach ($aAvailableModules as $sModuleId => $aModule) {
if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE)) {
continue;
} else {
$aSelectedModules[] = $sModuleId;
}
}
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation');
$oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade');
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseCreation');
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation');
$oRuntimeEnv->UpdatePredefinedObjects();
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseSetup');
$oRuntimeEnv->LoadData($aAvailableModules, false /* no sample data*/);
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDataLoad');
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup');
$oRuntimeEnv->LoadData($aAvailableModules, $aSelectedModules, false /* no sample data*/);
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDataLoad');
$sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion();
$oExtensionsMap = new iTopExtensionsMap();
// Default choices = as before
@@ -179,7 +187,7 @@ final class CoreUpdater
$oRuntimeEnv->RecordInstallation(
$oConfig,
$sDataModelVersion,
array_keys($aAvailableModules),
$aSelectedModules,
$aSelectedExtensionCodes,
'Done by the iTop Core Updater'
);

View File

@@ -135,7 +135,7 @@ class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment
$aAvailableModules[$oModule->GetName()] = $oModule;
}
// TODO check the auto-selected modules here
foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) {
foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) {
if ($oExtension->bMarkedAsChosen) {
foreach ($oExtension->aModules as $sModuleName) {
if (!isset($aRet[$sModuleName]) && isset($aAvailableModules[$sModuleName])) {

View File

@@ -24,13 +24,129 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\HubConnector\Controller\HubController;
use Combodo\iTop\Application\WebPage\JsonPage;
require_once(APPROOT.'application/utils.inc.php');
require_once(APPROOT.'core/log.class.inc.php');
IssueLog::Enable(APPROOT.'log/error.log');
require_once(__DIR__.'/src/Controller/HubController.php');
require_once(APPROOT.'setup/runtimeenv.class.inc.php');
require_once(APPROOT.'setup/backup.class.inc.php');
require_once(APPROOT.'core/mutex.class.inc.php');
require_once(APPROOT.'core/dict.class.inc.php');
require_once(APPROOT.'setup/xmldataloader.class.inc.php');
require_once(__DIR__.'/hubruntimeenvironment.class.inc.php');
/**
* Overload of DBBackup to handle logging
*/
class DBBackupWithErrorReporting extends DBBackup
{
protected $aInfos = [];
protected $aErrors = [];
protected function LogInfo($sMsg)
{
$aInfos[] = $sMsg;
}
protected function LogError($sMsg)
{
IssueLog::Error($sMsg);
$aErrors[] = $sMsg;
}
public function GetInfos()
{
return $this->aInfos;
}
public function GetErrors()
{
return $this->aErrors;
}
}
/**
*
* @param string $sTargetFile
* @throws Exception
* @return DBBackupWithErrorReporting
*/
function DoBackup($sTargetFile)
{
// Make sure the target directory exists
$sBackupDir = dirname($sTargetFile);
SetupUtils::builddir($sBackupDir);
$oBackup = new DBBackupWithErrorReporting();
$oBackup->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''));
$sSourceConfigFile = APPCONF.utils::GetCurrentEnvironment().'/'.ITOP_CONFIG_FILE;
$oMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment());
$oMutex->Lock();
try {
$oBackup->CreateCompressedBackup($sTargetFile, $sSourceConfigFile);
} catch (Exception $e) {
$oMutex->Unlock();
throw $e;
}
$oMutex->Unlock();
return $oBackup;
}
/**
* Outputs the status of the current ajax execution (as a JSON structure)
*
* @param string $sMessage
* @param bool $bSuccess
* @param number $iErrorCode
* @param array $aMoreFields
* Extra fields to pass to the caller, if needed
*/
function ReportStatus($sMessage, $bSuccess, $iErrorCode = 0, $aMoreFields = [])
{
// Do not use AjaxPage during setup phases, because it uses InterfaceDiscovery in Twig compilation
$oPage = new JsonPage();
$aResult = [
'code' => $iErrorCode,
'message' => $sMessage,
'fields' => $aMoreFields,
];
$oPage->SetData($aResult);
$oPage->SetOutputDataOnly(true);
$oPage->output();
}
/**
* Helper to output the status of a successful execution
*
* @param string $sMessage
* @param array $aMoreFields
* Extra fields to pass to the caller, if needed
*/
function ReportSuccess($sMessage, $aMoreFields = [])
{
ReportStatus($sMessage, true, 0, $aMoreFields);
}
/**
* Helper to output the status of a failed execution
*
* @param string $sMessage
* @param number $iErrorCode
* @param array $aMoreFields
* Extra fields to pass to the caller, if needed
*/
function ReportError($sMessage, $iErrorCode, $aMoreFields = [])
{
if ($iErrorCode == 0) {
// 0 means no error, so change it if no meaningful error code is supplied
$iErrorCode = -1;
}
ReportStatus($sMessage, false, $iErrorCode, $aMoreFields);
}
try {
SetupUtils::ExitMaintenanceMode(false); // Reset maintenance mode in case of problem
@@ -67,7 +183,7 @@ try {
foreach ($aChecks as $oCheckResult) {
if ($oCheckResult->iSeverity == CheckResult::ERROR) {
$bFailed = true;
HubController::GetInstance()->ReportError($oCheckResult->sLabel, -2);
ReportError($oCheckResult->sLabel, -2);
}
}
if (!$bFailed) {
@@ -75,27 +191,169 @@ try {
$fFreeSpace = SetupUtils::CheckDiskSpace($sDBBackupPath);
if ($fFreeSpace !== false) {
$sMessage = Dict::Format('iTopHub:BackupFreeDiskSpaceIn', SetupUtils::HumanReadableSize($fFreeSpace), dirname($sDBBackupPath));
HubController::GetInstance()->ReportSuccess($sMessage);
ReportSuccess($sMessage);
} else {
HubController::GetInstance()->ReportError(Dict::S('iTopHub:FailedToCheckFreeDiskSpace'), -1);
ReportError(Dict::S('iTopHub:FailedToCheckFreeDiskSpace'), -1);
}
}
break;
case 'do_backup':
HubController::GetInstance()->LaunchBackup();
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
try {
if (MetaModel::GetConfig()->Get('demo_mode')) {
throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
}
SetupLog::Info('Backup starts...');
set_time_limit(0);
$sBackupPath = APPROOT.'/data/backups/manual/backup-';
$iSuffix = 1;
$sSuffix = '';
// Generate a unique name...
do {
$sBackupFile = $sBackupPath.date('Y-m-d-His').$sSuffix;
$sSuffix = '-'.$iSuffix;
$iSuffix++ ;
} while (file_exists($sBackupFile));
$oBackup = DoBackup($sBackupFile);
$aErrors = $oBackup->GetErrors();
if (count($aErrors) > 0) {
SetupLog::Error('Backup failed.');
SetupLog::Error(implode("\n", $aErrors));
ReportError(Dict::S('iTopHub:BackupFailed'), -1, $aErrors);
} else {
SetupLog::Info('Backup successfully completed.');
ReportSuccess(Dict::S('iTopHub:BackupOk'));
}
} catch (Exception $e) {
SetupLog::Error($e->getMessage());
ReportError($e->getMessage(), $e->getCode());
}
break;
case 'compile':
HubController::GetInstance()->LaunchCompile();
SetupLog::Info('Deployment starts...');
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) {
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
}
// First step: prepare the datamodel, if it fails, roll-back
$aSelectedExtensionCodes = utils::ReadParam('extension_codes', []);
$aSelectedExtensionDirs = utils::ReadParam('extension_dirs', []);
$oRuntimeEnv = new HubRunTimeEnvironment('production', false); // use a temp environment: production-build
$oRuntimeEnv->MoveSelectedExtensions(APPROOT.'/data/downloaded-extensions/', $aSelectedExtensionDirs);
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
if ($oConfig->Get('demo_mode')) {
throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
}
$aSelectModules = $oRuntimeEnv->CompileFrom('production', false); // WARNING symlinks does not seem to be compatible with manual Commit
$oRuntimeEnv->UpdateIncludes($oConfig);
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
// Safety check: check the inter dependencies, will throw an exception in case of inconsistency
$oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
$oRuntimeEnv->CheckMetaModel(); // Will throw an exception if a problem is detected
// Everything seems Ok so far, commit in env-production!
$oRuntimeEnv->WriteConfigFileSafe($oConfig);
$oRuntimeEnv->Commit();
// Report the success in a way that will be detected by the ajax caller
SetupLog::Info('Compilation completed...');
ReportSuccess('Ok'); // No access to Dict::S here
break;
case 'move_to_production':
HubController::GetInstance()->LaunchDeploy();
// Second step: update the schema and the data
// Everything happening below is based on env-production
$oRuntimeEnv = new RunTimeEnvironment('production', true);
try {
SetupLog::Info('Move to production starts...');
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) {
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
}
unlink(utils::GetDataPath().'hub/compile_authent');
// Load the "production" config file to clone & update it
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
SetupUtils::EnterReadOnlyMode($oConfig);
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
$aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
$aSelectedModules = [];
foreach ($aAvailableModules as $sModuleId => $aModule) {
if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE)) {
continue;
} else {
$aSelectedModules[] = $sModuleId;
}
}
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation');
$oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade');
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation');
$oRuntimeEnv->UpdatePredefinedObjects();
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup');
$oRuntimeEnv->LoadData($aAvailableModules, $aSelectedModules, false /* no sample data*/);
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDataLoad');
// Record the installation so that the "about box" knows about the installed modules
$sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion();
$oExtensionsMap = new iTopExtensionsMap();
// Default choices = as before
$oExtensionsMap->LoadChoicesFromDatabase($oConfig);
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) {
// Plus all "remote" extensions
if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE) {
$oExtensionsMap->MarkAsChosen($oExtension->sCode);
}
}
$aSelectedExtensionCodes = [];
foreach ($oExtensionsMap->GetChoices() as $oExtension) {
$aSelectedExtensionCodes[] = $oExtension->sCode;
}
$aSelectedExtensions = $oExtensionsMap->GetChoices();
$oRuntimeEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModules, $aSelectedExtensionCodes, 'Done by the iTop Hub Connector');
// Report the success in a way that will be detected by the ajax caller
SetupLog::Info('Deployment successfully completed.');
ReportSuccess(Dict::S('iTopHub:CompiledOK'));
} catch (Exception $e) {
if (file_exists(utils::GetDataPath().'hub/compile_authent')) {
unlink(utils::GetDataPath().'hub/compile_authent');
}
// Note: at this point, the dictionnary is not necessarily loaded
SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
SetupLog::Error('Debug trace: '.$e->getTraceAsString());
ReportError($e->getMessage(), $e->getCode());
} finally {
SetupUtils::ExitReadOnlyMode();
}
break;
default:
HubController::GetInstance()->ReportError("Invalid operation: '$sOperation'", -1);
ReportError("Invalid operation: '$sOperation'", -1);
}
} catch (Exception $e) {
SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
@@ -103,5 +361,5 @@ try {
utils::PopArchiveMode();
HubController::GetInstance()->ReportError($e->getMessage(), $e->getCode());
ReportError($e->getMessage(), $e->getCode());
}

View File

@@ -1,17 +1,9 @@
<?php
namespace Combodo\iTop\HubConnector\setup;
use Config;
use Exception;
use RunTimeEnvironment;
use SetupUtils;
class HubRunTimeEnvironment extends RunTimeEnvironment
{
/**
* Constructor
*
* @param string $sEnvironment
* @param string $bAutoCommit
*/
@@ -32,7 +24,6 @@ class HubRunTimeEnvironment extends RunTimeEnvironment
/**
* Update the includes for the target environment
*
* @param Config $oConfig
*/
public function UpdateIncludes(Config $oConfig)
@@ -42,9 +33,7 @@ class HubRunTimeEnvironment extends RunTimeEnvironment
/**
* Move an extension (path to folder of this extension) to the target environment
*
* @param string $sExtensionDirectory The folder of the extension
*
* @throws Exception
*/
public function MoveExtension($sExtensionDirectory)
@@ -68,10 +57,8 @@ class HubRunTimeEnvironment extends RunTimeEnvironment
/**
* Move the selected extensions located in the given directory in data/<target-env>-modules
*
* @param string $sDownloadedExtensionsDir The directory to scan
* @param string[] $aSelectedExtensionDirs The list of folders to move
*
* @throws Exception
*/
public function MoveSelectedExtensions($sDownloadedExtensionsDir, $aSelectedExtensionDirs)

View File

@@ -186,7 +186,9 @@ function collect_configuration()
// iTop modules
$oConfig = MetaModel::GetConfig();
$aInstalledModules = ModuleInstallationRepository::GetInstance()->ReadFromDB($oConfig);
$sLatestInstallationDate = CMDBSource::QueryToScalar("SELECT max(installed) FROM ".$oConfig->Get('db_subname')."priv_module_install");
// Get the latest installed modules, without the "root" ones (iTop version and datamodel version)
$aInstalledModules = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install WHERE installed = '".$sLatestInstallationDate."' AND parent_id != 0");
foreach ($aInstalledModules as $aDBInfo) {
$aConfiguration['itop_modules'][$aDBInfo['name']] = $aDBInfo['version'];

View File

@@ -1,300 +0,0 @@
<?php
namespace Combodo\iTop\HubConnector\Controller;
use Combodo\iTop\Application\WebPage\JsonPage;
use Combodo\iTop\HubConnector\Model\DBBackupWithErrorReporting;
use Combodo\iTop\HubConnector\setup\HubRunTimeEnvironment;
use Config;
use Dict;
use Exception;
use iTopExtension;
use iTopExtensionsMap;
use iTopMutex;
use LoginWebPage;
use MetaModel;
use MFCompiler;
use RunTimeEnvironment;
use SecurityException;
use SetupLog;
use SetupUtils;
use utils;
require_once(APPROOT.'setup/runtimeenv.class.inc.php');
require_once(APPROOT.'setup/backup.class.inc.php');
require_once(APPROOT.'core/mutex.class.inc.php');
require_once(APPROOT.'core/dict.class.inc.php');
require_once(APPROOT.'setup/xmldataloader.class.inc.php');
require_once(__DIR__.'/../setup/hubruntimeenvironment.class.inc.php');
class HubController
{
private static HubController $oInstance;
protected $bOutputHeaders = false;
protected function __construct()
{
}
final public static function GetInstance(): HubController
{
if (!isset(self::$oInstance)) {
self::$oInstance = new HubController();
}
return self::$oInstance;
}
final public static function SetInstance(?HubController $oInstance): void
{
self::$oInstance = $oInstance;
}
public function LaunchBackup()
{
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
try {
if (MetaModel::GetConfig()->Get('demo_mode')) {
throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
}
SetupLog::Info('Backup starts...');
set_time_limit(0);
$sBackupPath = APPROOT.'/data/backups/manual/backup-';
$iSuffix = 1;
$sSuffix = '';
// Generate a unique name...
do {
$sBackupFile = $sBackupPath.date('Y-m-d-His').$sSuffix;
$sSuffix = '-'.$iSuffix;
$iSuffix++ ;
} while (file_exists($sBackupFile));
$oBackup = $this->DoBackup($sBackupFile);
$aErrors = $oBackup->GetErrors();
if (count($aErrors) > 0) {
SetupLog::Error('Backup failed.');
SetupLog::Error(implode("\n", $aErrors));
$this->ReportError(Dict::S('iTopHub:BackupFailed'), -1, $aErrors);
} else {
SetupLog::Info('Backup successfully completed.');
$this->ReportSuccess(Dict::S('iTopHub:BackupOk'));
}
} catch (Exception $e) {
SetupLog::Error($e->getMessage());
$this->ReportError($e->getMessage(), $e->getCode());
}
}
/**
*
* @param string $sTargetFile
* @throws Exception
* @return DBBackupWithErrorReporting
*/
public function DoBackup($sTargetFile): DBBackupWithErrorReporting
{
// Make sure the target directory exists
$sBackupDir = dirname($sTargetFile);
SetupUtils::builddir($sBackupDir);
$oBackup = new DBBackupWithErrorReporting();
$oBackup->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''));
$sSourceConfigFile = APPCONF.utils::GetCurrentEnvironment().'/'.ITOP_CONFIG_FILE;
$oMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment());
$oMutex->Lock();
try {
$oBackup->CreateCompressedBackup($sTargetFile, $sSourceConfigFile);
} catch (Exception $e) {
$oMutex->Unlock();
throw $e;
}
$oMutex->Unlock();
return $oBackup;
}
public function LaunchCompile()
{
SetupLog::Info('Deployment starts...');
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) {
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
}
// First step: prepare the datamodel, if it fails, roll-back
$aSelectedExtensionCodes = utils::ReadParam('extension_codes', []);
$aSelectedExtensionDirs = utils::ReadParam('extension_dirs', []);
$oRuntimeEnv = new HubRunTimeEnvironment('production', false); // use a temp environment: production-build
$oRuntimeEnv->MoveSelectedExtensions(APPROOT.'/data/downloaded-extensions/', $aSelectedExtensionDirs);
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
if ($oConfig->Get('demo_mode')) {
throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
}
$aSelectModules = $oRuntimeEnv->CompileFrom('production'); // WARNING symlinks does not seem to be compatible with manual Commit
$oRuntimeEnv->UpdateIncludes($oConfig);
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
// Safety check: check the inter dependencies, will throw an exception in case of inconsistency
$oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
$oRuntimeEnv->CheckMetaModel(); // Will throw an exception if a problem is detected
// Everything seems Ok so far, commit in env-production!
$oRuntimeEnv->WriteConfigFileSafe($oConfig);
$oRuntimeEnv->Commit();
// Report the success in a way that will be detected by the ajax caller
SetupLog::Info('Compilation completed...');
$this->ReportSuccess('Ok'); // No access to Dict::S here
}
public function LaunchDeploy()
{
// Second step: update the schema and the data
// Everything happening below is based on env-production
$oRuntimeEnv = new RunTimeEnvironment('production', true);
try {
SetupLog::Info('Move to production starts...');
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) {
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
}
unlink(utils::GetDataPath().'hub/compile_authent');
// Load the "production" config file to clone & update it
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
SetupUtils::EnterReadOnlyMode($oConfig);
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);
$aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true);
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'BeforeDatabaseCreation');
$oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade');
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseCreation');
$oRuntimeEnv->UpdatePredefinedObjects();
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseSetup');
$oRuntimeEnv->LoadData($aAvailableModules, false /* no sample data*/);
$oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDataLoad');
// Record the installation so that the "about box" knows about the installed modules
$sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion();
$oExtensionsMap = new iTopExtensionsMap();
// Default choices = as before
$oExtensionsMap->LoadChoicesFromDatabase($oConfig);
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) {
// Plus all "remote" extensions
if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE) {
$oExtensionsMap->MarkAsChosen($oExtension->sCode);
}
}
$aSelectedExtensionCodes = [];
foreach ($oExtensionsMap->GetChoices() as $oExtension) {
$aSelectedExtensionCodes[] = $oExtension->sCode;
}
$aSelectedExtensions = $oExtensionsMap->GetChoices();
$oRuntimeEnv->RecordInstallation($oConfig, $sDataModelVersion, array_keys($aAvailableModules), $aSelectedExtensionCodes, 'Done by the iTop Hub Connector');
// Report the success in a way that will be detected by the ajax caller
SetupLog::Info('Deployment successfully completed.');
$this->ReportSuccess(Dict::S('iTopHub:CompiledOK'));
} catch (Exception $e) {
if (file_exists(utils::GetDataPath().'hub/compile_authent')) {
unlink(utils::GetDataPath().'hub/compile_authent');
}
// Note: at this point, the dictionnary is not necessarily loaded
SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
SetupLog::Error('Debug trace: '.$e->getTraceAsString());
$this->ReportError($e->getMessage(), $e->getCode());
} finally {
SetupUtils::ExitReadOnlyMode();
}
}
/**
* Outputs the status of the current ajax execution (as a JSON structure)
*
* @param string $sMessage
* @param bool $bSuccess
* @param number $iErrorCode
* @param array $aMoreFields
* Extra fields to pass to the caller, if needed
*/
public function ReportStatus($sMessage, $bSuccess, $iErrorCode = 0, $aMoreFields = [])
{
// Do not use AjaxPage during setup phases, because it uses InterfaceDiscovery in Twig compilation
$this->oLastJsonPage = new JsonPage();
$this->oLastJsonPage->SetOutputHeaders($this->bOutputHeaders);
$aResult = [
'code' => $iErrorCode,
'message' => $sMessage,
'fields' => $aMoreFields,
];
$this->oLastJsonPage->SetData($aResult);
$this->oLastJsonPage->SetOutputDataOnly(true);
$this->oLastJsonPage->output();
}
private ?JsonPage $oLastJsonPage = null;
public function GetLastJsonPage(): ?JsonPage
{
return $this->oLastJsonPage;
}
/**
* Helper to output the status of a successful execution
*
* @param string $sMessage
* @param array $aMoreFields
* Extra fields to pass to the caller, if needed
*/
public function ReportSuccess($sMessage, $aMoreFields = [])
{
$this->ReportStatus($sMessage, true, 0, $aMoreFields);
}
/**
* Helper to output the status of a failed execution
*
* @param string $sMessage
* @param number $iErrorCode
* @param array $aMoreFields
* Extra fields to pass to the caller, if needed
*/
public function ReportError($sMessage, $iErrorCode, $aMoreFields = [])
{
if ($iErrorCode == 0) {
// 0 means no error, so change it if no meaningful error code is supplied
$iErrorCode = -1;
}
$this->ReportStatus($sMessage, false, $iErrorCode, $aMoreFields);
}
/**
* Dont print headers for testing purpose mainly
* @param bool bOutputHeaders
*
* @return void
*/
public function SetOutputHeaders(bool $bOutputHeaders): void
{
$this->bOutputHeaders = $bOutputHeaders;
}
}

View File

@@ -1,37 +0,0 @@
<?php
namespace Combodo\iTop\HubConnector\Model;
use DBBackup;
use IssueLog;
/**
* Overload of DBBackup to handle logging
*/
class DBBackupWithErrorReporting extends DBBackup
{
protected $aInfos = [];
protected $aErrors = [];
protected function LogInfo($sMsg)
{
$this->aInfos[] = $sMsg;
}
protected function LogError($sMsg)
{
IssueLog::Error($sMsg);
$this->aErrors[] = $sMsg;
}
public function GetInfos(): array
{
return $this->aInfos;
}
public function GetErrors(): array
{
return $this->aErrors;
}
}

View File

@@ -306,11 +306,8 @@
<is_null_allowed>true</is_null_allowed>
</field>
<field id="servicesubcategory_id" xsi:type="AttributeExternalKey">
<filter><![CDATA[SELECT ServiceSubcategory WHERE service_id = :this->service_id AND (ISNULL(:this->request_type) OR request_type = :this->request_type) AND status != 'obsolete']]></filter>
<dependencies>
<attribute id="service_id"/>
<attribute id="request_type"/>
</dependencies>
<filter><![CDATA[SELECT ServiceSubcategory WHERE service_id = :this->service_id AND status != 'obsolete']]></filter>
<dependencies/>
<sql>servicesubcategory_id</sql>
<target_class>ServiceSubcategory</target_class>
<is_null_allowed>true</is_null_allowed>
@@ -1334,21 +1331,23 @@
// Compute the priority of the ticket
$this->Set('priority', $this->ComputePriority());
// Compute the request_type if not already defined (by the user)
$sType = $this->Get('request_type');
if (is_null($sType) || ($sType === ''))
{
$iSvcSubcat = $this->Get('servicesubcategory_id');
if ($iSvcSubcat != 0)
{
$oSvcSubcat = MetaModel::GetObject(ServiceSubcategory::class, $iSvcSubcat, true, true);
$this->Set('request_type', $oSvcSubcat->Get('request_type'));
}
}
return parent::ComputeValues();
}]]></code>
</method>
<method id="EvtComputeRequestType">
<static>false</static>
<access>public</access>
<type>EventListener</type>
<code><![CDATA[ public function EvtComputeRequestType(?Combodo\iTop\Service\Events\EventData $oEventData = null)
{
$iSvcSubcat = $this->Get('servicesubcategory_id');
if ($iSvcSubcat != 0)
{
$oSvcSubcat = MetaModel::GetObject(ServiceSubcategory::class, $iSvcSubcat, true, true);
$this->Set('request_type', $oSvcSubcat->Get('request_type'));
}
}]]></code>
</method>
<method id="DisplayBareRelations">
<static>false</static>
<access>public</access>
@@ -1528,6 +1527,13 @@
}]]></code>
</method>
</methods>
<event_listeners>
<event_listener id="EVENT_DB_BEFORE_WRITE">
<event>EVENT_DB_BEFORE_WRITE</event>
<callback>EvtComputeRequestType</callback>
<rank>0</rank>
</event_listener>
</event_listeners>
<presentation>
<details>
<items>

View File

@@ -12,7 +12,8 @@ SetupWebPage::AddModule(
// Setup
//
'dependencies' => [
'itop-structure/2.7.1 || itop-portal/3.0.0', // itop-portal : module_design_itop_design->module_designs->itop-portal
'itop-structure/2.7.1',
'itop-portal/3.0.0', // module_design_itop_design->module_designs->itop-portal
],
'mandatory' => false,
'visible' => true,

File diff suppressed because it is too large Load Diff

View File

@@ -1279,6 +1279,7 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
'UI:DashletGroupBy:Prop-GroupBy:DayOfMonth' => 'Jour du mois pour %1$s',
'UI:DashletGroupBy:Prop-GroupBy:Select-Hour' => '%1$s (heure)',
'UI:DashletGroupBy:Prop-GroupBy:Select-Month' => '%1$s (mois)',
'UI:DashletGroupBy:Prop-GroupBy:Select-Year' => '%1$s (année)',
'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfWeek' => '%1$s (jour de la semaine)',
'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfMonth' => '%1$s (jour du mois)',
'UI:DashletGroupBy:MissingGroupBy' => 'Veuillez sélectionner le champ sur lequel les objets seront groupés',
@@ -1544,7 +1545,8 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
'UI:Search:Criteria:HierarchicalKey:ChildrenIncluded:Hint' => 'Les descendants des objets sélectionnés seront inclus.',
'UI:Search:Criteria:Raw:Filtered' => 'Filtré',
'UI:Search:Criteria:Raw:FilteredOn' => 'Filtré sur %1$s',
'UI:StateChanged' => 'Etat modifié',
'UI:StateChanged' => 'État modifié',
'UI:AddSubTree' => 'Ajouter une entrée',
]);
//

View File

@@ -19,8 +19,15 @@
*/
// Input
Dict::Add('EN US', 'English', 'English', [
'UI:Component:Input:ChangeNotAllowed' => 'This change is not allowed',
'UI:Component:Input:Password:DoesNotMatch' => 'Passwords do not match',
'UI:Component:Input:Set:MinimumItems' => 'Minimum %1$s item(s) required',
]);
Dict::Add(
'EN US',
'English',
'English',
[
'UI:Component:Input:ChangeNotAllowed' => 'This change is not allowed',
'UI:Component:Input:Password:DoesNotMatch' => 'Passwords do not match',
'UI:Component:Input:Set:MinimumItems' => 'Minimum %1$s item(s) required',
'UI:Component:Input:Select:Select_item' => 'Select an item...',
]
);

View File

@@ -10,8 +10,15 @@
/**
*
*/
Dict::Add('FR FR', 'French', 'Français', [
'UI:Component:Input:ChangeNotAllowed' => 'Cette modification n\'est pas autorisée',
'UI:Component:Input:Password:DoesNotMatch' => 'Les mots de passe ne correspondent pas',
'UI:Component:Input:Set:MinimumItems' => 'Minimum %1$s élément(s) requis',
]);
Dict::Add(
'FR FR',
'French',
'Français',
[
'UI:Component:Input:ChangeNotAllowed' => 'Cette modification n\'est pas autorisée',
'UI:Component:Input:Password:DoesNotMatch' => 'Les mots de passe ne correspondent pas',
'UI:Component:Input:Set:MinimumItems' => 'Minimum %1$s élément(s) requis',
'UI:Component:Input:Select:Select_item' => 'Sélectionnez un élément...',
]
);

17
git-split.md Normal file
View File

@@ -0,0 +1,17 @@
git copy of one file into two files without loosing history
```
git mv foo bar
git commit
SAVED=`git rev-parse HEAD`
git reset --hard HEAD^
git mv foo copy
git commit
git merge $SAVED # This will generate conflicts
git commit -a # Trivially resolved like this
git mv copy foo
git commit
```

View File

@@ -0,0 +1,70 @@
/**
* Image renderer plugin for TomSelect
*/
TomSelect.define('image_renderer', function(options) {
this.settings.render.option = function(data, escape) {
return `<div class="ibo-input-select-icon--menu--item">
<img src="${options['images_resource_path']+escape(data.value)}" alt="${data.text}" />${escape(data.text)}
</div>`;
};
this.settings.render.item = function(data, escape) {
return `<div class="ibo-input-select-icon--menu--item">
<img src="${options['images_resource_path']+escape(data.value)}" alt="${data.text}"/>${escape(data.text)}
</div>`;
};
});
class ChoicesElement extends HTMLSelectElement {
// register the custom element
static {
customElements.define('choices-element', ChoicesElement, {extends: 'select'});
}
plugins = [];
connectedCallback() {
if (this.tomselect) {
return;
}
if (this.getAttribute('multiple')) {
this.plugins.push('remove_button');
}
// plugins
if(this.hasAttribute('data-plugins')){
const aPlugins = JSON.parse(this.getAttribute('data-plugins'));
Array.from(aPlugins).values().forEach(plugin => {
this.plugins.push(plugin);
});
}
const options = {
plugins: this.plugins,
wrapperClass: 'ts-wrapper ibo-input-wrapper ibo-input-select-wrapper--with-buttons ibo-input-select-autocomplete-wrapper',
controlClass: 'ts-control ibo-input ibo-input-select ibo-input-select-autocomplete',
dropdownParent: 'body',
render: {
dropdown: function (data, escape) {
return `<div class="selectize-dropdown"></div>`;
}
}
};
if (this.getAttribute('data-tom-select-disable-auto-complete')) {
options.controlInput = null;
}
if (this.getAttribute('data-tom-select-max-items-selected') && this.getAttribute('data-tom-select-max-items-selected') !== '') {
options.maxItems = parseInt(this.getAttribute('data-tom-select-max-items-selected'));
}
if (this.getAttribute('data-tom-select-placehelder')) {
options.placeholder = this.getAttribute('data-tom-select-placehelder');
}
new TomSelect(this, options);
}
}

View File

@@ -0,0 +1,39 @@
class CollectionElement extends HTMLElement {
#eBtnAdd;
// register the custom element
static {
customElements.define('collection-element', CollectionElement);
}
addFormToCollection(e) {
const collectionHolder = document.querySelector('.'+e.currentTarget.dataset.collectionHolderClass);
const item = document.createElement('div');
const collectionHolderList = collectionHolder.querySelector('[role="list"]');
item.innerHTML = collectionHolder
.dataset
.prototype
.replace(
/__name__/g,
collectionHolder.dataset.index
);
collectionHolderList.appendChild(item.firstChild);
collectionHolder.dataset.index++;
this.querySelectorAll('collection-entry-element').forEach((entry) => {
console.log('test');
entry.updateButtonStates();
});
}
/** connectedCallback **/
connectedCallback() {
this.#eBtnAdd = this.querySelector('.add_item_link');
this.#eBtnAdd.addEventListener('click', this.addFormToCollection.bind(this));
}
}

View File

@@ -0,0 +1,112 @@
class CollectionEntryElement extends HTMLElement {
// Button elements
#eBtnDelete;
#eBtnMoveUp;
#eBtnMoveDown;
// register the custom element
static {
customElements.define('collection-entry-element', CollectionEntryElement);
}
/** connectedCallback **/
connectedCallback() {
if ((this.dataset.new || this.dataset.allowDelete) && this.#eBtnDelete === undefined) {
this.#eBtnDelete = this.#createButton('Remove', 'ibo-button ibo-is-regular ibo-is-danger');
this.#eBtnDelete.addEventListener('click', this.#removeCollectionItem.bind(this));
this.appendChild(this.#eBtnDelete);
}
if (this.dataset.allowOrdering) {
if (this.#eBtnMoveUp === undefined) {
this.#eBtnMoveUp = this.#createButton('Move Up', 'ibo-button ibo-is-regular');
this.#eBtnMoveUp.addEventListener('click', this.#moveUp.bind(this));
this.appendChild(this.#eBtnMoveUp);
}
if (this.#eBtnMoveDown === undefined) {
this.#eBtnMoveDown = this.#createButton('Move Down', 'ibo-button ibo-is-regular');
this.#eBtnMoveDown.addEventListener('click', this.#moveDown.bind(this));
this.appendChild(this.#eBtnMoveDown);
}
}
this.updateButtonStates();
}
/**
* Update the state of the buttons (enabled/disabled).
*
*/
updateButtonStates() {
if (this.dataset.allowOrdering) {
if (this.previousElementSibling === null) {
this.#eBtnMoveUp.setAttribute('disabled', 'disabled');
} else {
this.#eBtnMoveUp.removeAttribute('disabled');
}
if (this.nextElementSibling === null) {
this.#eBtnMoveDown.setAttribute('disabled', 'disabled');
} else {
this.#eBtnMoveDown.removeAttribute('disabled');
}
}
}
/**
* Create a button element.
*
* @param label
* @param className
* @returns {HTMLButtonElement}
*/
#createButton(label, className) {
const btnElement = document.createElement('button');
btnElement.type = 'button';
btnElement.className = className;
btnElement.textContent = label;
return btnElement;
}
/**
* Move this collection item up.
*
*/
#moveUp() {
const prev = this.previousElementSibling;
if (prev) {
this.parentNode.insertBefore(this, prev);
this.updateButtonStates();
prev.updateButtonStates();
}
}
/**
* Move this collection item down.
*
*/
#moveDown() {
const next = this.nextElementSibling;
if (next) {
this.parentNode.insertBefore(next, this);
this.updateButtonStates();
next.updateButtonStates();
}
}
/**
* Remove this collection item.
*
*/
#removeCollectionItem() {
this.remove();
}
}

95
js/forms/form_element.js Normal file
View File

@@ -0,0 +1,95 @@
class FormElement extends HTMLFormElement
{
static #TURBO_REFRESHING_CLASS = 'turbo-refreshing';
static #TURBO_TRIGGER_FIELD = '_turbo_trigger';
#aFormBlockDataTransmittedData = {};
// register the custom element
static {
customElements.define('itop-form-element', FormElement, {extends: 'form'});
}
TriggerTurbo(oElement) {
// Get the name and id of the element triggering turbo
const sName = oElement.getAttribute('name');
const sId = oElement.getAttribute('id');
if(FormElement.IsCheckbox(oElement) || this.#aFormBlockDataTransmittedData[sName] !== oElement.value) {
// Refresh UI
this.#StartRefreshingUI(sId);
// Pre Submit
this.#PreSubmitTurboForm(sName);
// Submit
oElement.form.requestSubmit();
// Post Submit
this.#PostSubmitTurboForm(sName)
this.#aFormBlockDataTransmittedData[sName] = oElement.value;
}
}
/**
* Start refreshing UI.
*
* @param sId
* @constructor
*/
#StartRefreshingUI(sId)
{
Array.from(this.querySelectorAll(`.ibo-content-block`)).forEach(block => {
if(block.dataset.impactedBy !== undefined){
const aImpactedBy = block.dataset.impactedBy.split(',');
if(aImpactedBy.includes(sId)){
block.classList.add(FormElement.#TURBO_REFRESHING_CLASS);
}
}
});
}
/**
* Pre submit the form.
* Set the turbo trigger field in the form and disable validation
*
* @param sName
* @constructor
*/
#PreSubmitTurboForm(sName)
{
this.querySelector(`[name="${this.getAttribute("name")}[${FormElement.#TURBO_TRIGGER_FIELD}]"]`).value = sName;
this.setAttribute('novalidate', true);
}
/**
* Post submit the form.
* Reset the turbo trigger field and restore form validation.
*
* @param sName
* @constructor
*/
#PostSubmitTurboForm(sName)
{
this.querySelector(`[name="${this.getAttribute("name")}[${FormElement.#TURBO_TRIGGER_FIELD}]"]`).value = null;
this.removeAttribute('novalidate');
}
/**
*
* @param oElement
* @returns {boolean}
*/
static IsCheckbox (oElement)
{
return oElement instanceof HTMLInputElement
&& oElement.getAttribute('type') === 'checkbox'
}
}

123
js/forms/oql_element.js Normal file
View File

@@ -0,0 +1,123 @@
class OqlElement extends HTMLTextAreaElement {
static #DEBONCE = 400;
// register the custom element
static{
customElements.define('oql-element', OqlElement, {extends: 'textarea'});
}
// variables
#url = '../pages/ajax.render.php?route=oql.validate_query';
#iconValid = 'fa-check-double';
#iconNotValid = 'fa-exclamation-triangle';
#debounceTimer = null;
#debounce = OqlElement.#DEBONCE;
/** connectedCallback **/
connectedCallback() {
this.addEventListener('input', this.#onInput.bind(this));
this.#callValidateQuery();
this.addEventListener('focus', this.#onFocus.bind(this));
const oBtnBook = this.closest('.ibo-content-block').querySelector('[data-role="ibo-button"][data-action="book"]');
oBtnBook.addEventListener('click', this.#search.bind(this))
const oBtnRun = this.closest('.ibo-content-block').querySelector('[data-role="ibo-button"][data-action="run"]');
oBtnRun.addEventListener('click', this.#run.bind(this))
}
/**
* Call oql verification with debounce when input event is fired.
*/
#onInput() {
if (this.#debounceTimer) clearTimeout(this.#debounceTimer);
this.#debounceTimer = setTimeout(() => {
this.#callValidateQuery(true);
}, this.#debounce);
}
/**
* Call oql verification with debounce when focus event is fired.
*/
#onFocus() {
this.#callValidateQuery();
}
/**
* Call the ajax to validate the query.
*
* @param fireChange flag to handle change event
*/
#callValidateQuery(fireChange = false) {
fetch(this.#url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Combodo-Ajax': true
},
body: JSON.stringify({
query: this.value
})
})
.then(response => response.json())
.then(response => {
// fire change event only if the query is valid
if (fireChange && response.is_valid){
this.#fireChangeEvent();
}
// update the icon color
const fieldEl = this.closest('.ibo-field');
const marqueeEl = fieldEl.querySelector('[role="marquee"]');
marqueeEl.style.color = response.is_valid ? 'green' : 'orange';
marqueeEl.classList.toggle(this.#iconNotValid, !response.is_valid);
marqueeEl.classList.toggle(this.#iconValid, response.is_valid);
marqueeEl.setAttribute('title', response.is_valid ? Dict.S(this.dataset.validQueryText) : Dict.S(this.dataset.invalidQueryText));
});
}
/**
* Fire a change event.
*/
#fireChangeEvent() {
const changeEvent = new Event('change', { bubbles: true, cancelable: true });
this.dispatchEvent(changeEvent);
}
#search(){
const sId = this.getAttribute('id');
const sDialogId = `ac_dlg_${sId}`;
const sModalTitle = Dict.S(this.dataset.modalTitleText);
const sEmptyText = Dict.S(this.dataset.emptyText);
// Instance the widget
const oACWidget = new ExtKeyWidget(sId, 'QueryOQL', 'SELECT QueryOQL WHERE is_template = \'yes\'', sModalTitle, true, null, null, true, true, 'oql');
oACWidget.emptyHtml = `<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p><${sEmptyText}/p></div>`;
// Store in window to be accessible from dialog
window[`oACWidget_${sId}`] = oACWidget;
// Open the dialog
if ($(`#${sDialogId}`).length === 0)
{
$('body').append(`<div id="${sDialogId}"></div>`);
$(`#${sDialogId}`).dialog({
width: $(window).width()*0.8,
height: $(window).height()*0.8,
autoOpen: false,
modal: true,
resizeStop: oACWidget.UpdateSizes,
});
}
// Start searching
oACWidget.Search();
}
#run(){
window.open('../pages/run_query.php?expression=' + encodeURI(this.value), '_blank');
}
}

View File

@@ -0,0 +1,28 @@
class TurboStreamEvent extends HTMLElement {
// register the custom element
static {
customElements.define('turbo-stream-event', TurboStreamEvent);
}
constructor() {
super();
this.style.display = 'none';
const event = new CustomEvent("itop:TurboStreamEvent", {
detail: {
id: this.getAttribute('id'),
form_id: this.dataset.formId,
block_class: this.dataset.formBlockClass,
view_data: this.dataset.viewData,
valid: this.dataset.valid,
},
});
console.log(event);
document.dispatchEvent(event);
}
}

View File

@@ -0,0 +1,83 @@
class IboGridSlot extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
/** @type {string} unique cell id */
this.id = '';
/** @type {number} */
this.iPosX = this.getAttribute('gs-x') ? parseInt(this.getAttribute('gs-x'), 10) : 0;
/** @type {number} */
this.iPostY = this.getAttribute('gs-y') ? parseInt(this.getAttribute('gs-y'), 10) : 0;
/** @type {number} */
this.iWidth = this.getAttribute('gs-w') ? parseInt(this.getAttribute('gs-w'), 10) : 1;
/** @type {number} */
this.iHeight = this.getAttribute('gs-h') ? parseInt(this.getAttribute('gs-h'), 10) : 1;
/** @type {IboDashlet|null} contained dashlet id */
this.sDashletId = null;
/** @type {IboDashlet|null} contained dashlet element */
this.oDashlet = this.querySelector('ibo-dashlet') || null;
/** @type {Object} freeform metadata */
this.meta = {};
}
static MakeNew(oDashletElem, aOptions = {}) {
const oSlot = document.createElement('ibo-dashboard-grid-slot');
oDashletElem.classList.add("grid-stack-item-content");
oSlot.appendChild(oDashletElem);
oSlot.classList.add("grid-stack-item");
oSlot.oDashlet = oDashletElem;
return oSlot;
}
Serialize(bIncludeHtml = false) {
const oDashlet = this.oDashlet;
const aSlotData = {
position_x: this.iPosX,
position_y: this.iPostY,
width: this.iWidth,
height: this.iHeight
};
const aDashletData = oDashlet ? oDashlet.Serialize(bIncludeHtml) : {};
return {
...aSlotData,
dashlet: {...aDashletData}
};
}
static observedAttributes = ['gs-x', 'gs-y', 'gs-w', 'gs-h'];
attributeChangedCallback(name, oldValue, newValue) {
switch (name) {
case 'gs-x':
this.iPosX = parseInt(newValue, 10) || 0;
break;
case 'gs-y':
this.iPostY = parseInt(newValue, 10) || 0;
break;
case 'gs-w':
this.iWidth = parseInt(newValue, 10) || 1;
break;
case 'gs-h':
this.iHeight = parseInt(newValue, 10) || 1;
break;
}
}
}
customElements.define('ibo-dashboard-grid-slot', IboGridSlot);

View File

@@ -0,0 +1,161 @@
class IboGrid extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
/** @type {number} */
this.columnsCount = 12;
/** @type {boolean} unused yet*/
this.bEditable = false;
/** @type {GridStack|null} GridStack instance */
this.oGrid = null;
/** @type {Array<IboGridSlot>} */
this.aSlots = [];
this.SetupGrid();
}
SetupGrid() {
let aCandidateSlots = Array.from(this.querySelectorAll('ibo-dashboard-grid-slot'));
aCandidateSlots.forEach(oSlot => {
const aAttrs = ['gs-x', 'gs-y', 'gs-w', 'gs-h', 'id'];
aAttrs.forEach(sAttr => {
const sVal = oSlot.getAttribute(sAttr) || oSlot.getAttribute('data-'+sAttr);
if (sVal !== null) {
oSlot.setAttribute(sAttr, sVal);
}
});
});
this.oGrid = GridStack.init({
column: this.columnsCount,
marginTop: 8,
marginLeft: 8,
marginRight: 0,
marginBottom: 0,
resizable: {handles: 'all'},
disableDrag: true,
disableResize: true,
float: true
}, this);
}
getSlots() {
return this.oGrid.getGridItems();
}
SetEditable(bIsEditable) {
this.bEditable = bIsEditable;
if (this.oGrid !== null) {
this.oGrid.enableMove(bIsEditable);
this.oGrid.enableResize(bIsEditable);
}
}
GetDashletElement(sDashletId) {
const aSlots = this.getSlots();
for (let oSlot of aSlots) {
if (oSlot.oDashlet && oSlot.oDashlet.sDashletId === sDashletId) {
return oSlot.oDashlet;
}
}
return null;
}
AddDashlet(sDashlet, aOptions = {}) {
// Get the dashlet as an object
const oParser = new DOMParser();
const oDocument = oParser.parseFromString(sDashlet, 'text/html');
const oDashlet = oDocument.body.firstChild;
const oSlot = IboGridSlot.MakeNew(oDashlet);
this.append(oSlot);
let aDefaultOptions = {
autoPosition: !(aOptions.hasOwnProperty('x') || aOptions.hasOwnProperty('y')),
}
this.oGrid.makeWidget(oSlot, Object.assign(aDefaultOptions, aOptions));
return oDashlet.sDashletId;
}
RefreshDashlet (sDashlet, aOptions = {}) {
const oParser = new DOMParser();
const oDocument = oParser.parseFromString(sDashlet, 'text/html');
const oNewDashlet = oDocument.body.firstElementChild;
// Can't use oNewDashet.sDashletId as it's not in the DOM yet and connectedCallback hasn't been called yet
const oExistingDashlet = this.GetDashletElement(oNewDashlet.getAttribute('data-dashlet-id') );
// Copy attributes
for (const sAttr of oNewDashlet.attributes) {
oExistingDashlet.setAttribute(sAttr.name, sAttr.value);
}
// If we refresh a dashlet, its parent slot remains the same, we just need to update its content
let oSlotForExistingDashlet = null;
const aSlots = this.getSlots();
for (let oSlot of aSlots) {
if (oSlot.oDashlet && oSlot.oDashlet.sDashletId === oNewDashlet.getAttribute('data-dashlet-id')) {
oSlotForExistingDashlet = oSlot;
break;
}
}
// There must be a slot for the existing dashlet
if(oSlotForExistingDashlet !== null) {
this.oGrid.removeWidget(oSlotForExistingDashlet);
oSlotForExistingDashlet.innerHTML = oNewDashlet.outerHTML;
this.oGrid.makeWidget(oSlotForExistingDashlet);
}
}
CloneDashlet(sDashletId) {
const aSlots = this.getSlots();
for (let oSlot of aSlots) {
if (oSlot.oDashlet && oSlot.oDashlet.sDashletId === sDashletId) {
const sWidth = oSlot.iWidth;
const sHeight = oSlot.iHeight;
// Ask a new rendered dashlet to avoid duplicating IDs
// Still we'll copy width and height
this.closest('ibo-dashboard')?.AddNewDashlet(oSlot.oDashlet.sType, oSlot.oDashlet.formData, {
'w': sWidth,
'h': sHeight
});
break;
}
}
}
RemoveDashlet(sDashletId) {
const aSlots = this.getSlots();
for (let oSlot of aSlots) {
if (oSlot.oDashlet && oSlot.oDashlet.sDashletId === sDashletId) {
this.oGrid.removeWidget(oSlot);
break;
}
}
}
ClearGrid() {
this.oGrid.removeAll();
}
Serialize(bIncludeHtml = false) {
const aSlots = this.getSlots();
return aSlots.reduce((aAccumulator, oSlot) => {
aAccumulator[oSlot.oDashlet.sDashletId] = oSlot.Serialize(bIncludeHtml);
return aAccumulator;
}, {});
}
}
customElements.define('ibo-dashboard-grid', IboGrid);

View File

@@ -0,0 +1,371 @@
class IboDashboard extends HTMLElement {
constructor() {
super();
/** @type {string} */
this.sId = "";
/** @type {string} */
this.sTitle = "";
/** @type {boolean} unused yet */
this.isEditable = false;
/** @type {boolean} */
this.bEditMode = false;
/** @type {boolean} unused yet */
this.bAutoRefresh = false;
/** @type {number} unused yet */
this.iRefreshRate = 0;
/** @type {IboGrid|null} */
this.oGrid = null;
/** @type {string|null} unused yet */
this.refreshUrl = null;
/** @type {string|null} unused yet */
this.csrfToken = null;
/** @type {number} Payload schema version */
this.schemaVersion = 2;
/** @type {object|null} Last saved state for cancel functionality, unused yet */
this.aLastSavedState = null;
}
connectedCallback() {
this.sId = this.getAttribute("id");
this.bEditMode = (this.getAttribute("data-edit-mode") === "edit");
this.SetupGrid();
this.BindEvents();
}
BindEvents() {
document.getElementById('ibo-dashboard-menu-edit-'+this.sId)?.addEventListener('click', (e) => {
e.preventDefault();
this.ToggleEditMode();
document.getElementById('ibo-dashboard-menu-edit-'+this.sId)?.classList.toggle('active', this.GetEditMode());
});
this.querySelector('[data-role="ibo-button"][name="save"]')?.addEventListener('click', (e) => {
e.preventDefault();
this.Save()
});
this.querySelector('[data-role="ibo-button"][name="cancel"]')?.addEventListener('click', (e) => {
e.preventDefault();
if (this.aLastSavedState) {
this.Load(this.aLastSavedState);
}
this.SetEditMode(false);
});
// TODO 3.3 Add event listener to dashboard toggler to get custom/default dashboard switching
// TODO 3.3 require load method that's not finished yet
// Bind IboDashboard object to these listener so we can access current instance
this._ListenToDashletFormSubmission = this._ListenToDashletFormSubmission.bind(this);
this._ListenToDashletFormCancellation = this._ListenToDashletFormCancellation.bind(this);
}
SetupGrid() {
if(this.oGrid !== null){
return;
}
this.oGrid = this.querySelector('ibo-dashboard-grid');
}
GetEditMode() {
return this.bEditMode;
}
ToggleEditMode(){
this.SetEditMode(!this.bEditMode);
}
SetEditMode(bEditMode) {
this.bEditMode = bEditMode;
this.oGrid.SetEditable(this.bEditMode);
if(this.bEditMode){
// TODO 3.3 If we are in default dashboard display, change to custom to allow editing
// TODO 3.3 Get the custom dashboard and load it, show a tooltip on the dashboard toggler to explain that we switched to custom mode
this.aLastSavedState = this.Serialize(true);
this.setAttribute("data-edit-mode", "edit");
}
else{
this.setAttribute("data-edit-mode", "view");
}
}
AddNewDashlet(sDashletClass, sDashletValues, aDashletOptions = {}) {
let sNewDashletUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.get_dashlet&dashlet_class='+encodeURIComponent(sDashletClass);
if(sDashletValues.length > 0) {
sNewDashletUrl += '&values=' + encodeURIComponent(sDashletValues);
}
fetch(sNewDashletUrl)
.then(async data => {
const sDashletId = this.oGrid.AddDashlet(await data.text(), aDashletOptions);
// TODO 3.3 Either open the dashlet form right away, or just enter edit mode
this.EditDashlet(sDashletId);
})
}
RefreshDashlet(oDashlet) {
let sGetDashletUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.get_dashlet&dashlet_class=' + encodeURIComponent(oDashlet.sType)
+'&dashlet_id=' + encodeURIComponent(oDashlet.sDashletId);
if(oDashlet.formData.length > 0) {
sGetDashletUrl += '&values=' + encodeURIComponent(oDashlet.formData);
}
return fetch(sGetDashletUrl)
.then(async data => {
this.oGrid.RefreshDashlet(await data.text());
});
}
HideDashletTogglers() {
const aTogglers = document.querySelector('.ibo-dashlet-panel--entries');
aTogglers.classList.add('ibo-is-hidden');
}
ShowDashletTogglers() {
const aTogglers = document.querySelector('.ibo-dashlet-panel--entries');
aTogglers.classList.remove('ibo-is-hidden');
}
SetDashletForm(sFormData) {
const oFormContainer = document.querySelector('.ibo-dashlet-panel--form-container');
oFormContainer.innerHTML = sFormData;
oFormContainer.classList.remove('ibo-is-hidden');
}
ClearDashletForm() {
const oFormContainer = document.querySelector('.ibo-dashlet-panel--form-container');
oFormContainer.innerHTML = '';
oFormContainer.classList.add('ibo-is-hidden');
}
DisableFormButtons() {
const aButtons = this.querySelectorAll('.ibo-dashboard--form--actions button');
aButtons.forEach( (oButton) => {
oButton.setAttribute('disabled', 'disabled');
});
}
EnableFormButtons() {
const aButtons = this.querySelectorAll('.ibo-dashboard--form--actions button');
aButtons.forEach( (oButton) => {
oButton.removeAttribute('disabled');
});
}
EditDashlet(sDashletId) {
const oDashlet = this.oGrid.GetDashletElement(sDashletId);
const me = this;
// Create backdrop to block interactions with other dashlets
if(this.oGrid.querySelector('.ibo-dashboard--grid--backdrop') === null) {
const oBackdrop = document.createElement("div");
oBackdrop.classList.add('ibo-dashboard--grid--backdrop');
this.oGrid.append(oBackdrop);
}
this.querySelector('ibo-dashlet[data-dashlet-id="'+sDashletId+'"]').setAttribute('data-edit-mode', 'edit');
// Disable dashboard buttons so we need to finish this edition first
this.DisableFormButtons();
// Fetch dashlet form from server
let sGetashletFormUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.get_dashlet_form&dashlet_class='+encodeURIComponent(oDashlet.sType);
if(oDashlet.formData.length > 0) {
sGetashletFormUrl += '&values=' + encodeURIComponent(oDashlet.formData);
}
fetch(sGetashletFormUrl)
.then(async formData => {
const sFormData = await formData.text();
this.HideDashletTogglers();
this.SetDashletForm(sFormData);
// Listen to form submission event and cancellation
document.addEventListener('itop:TurboStreamEvent', me._ListenToDashletFormSubmission);
document.querySelector('.ibo-dashlet-panel--form-container button[name="dashboard_cancel"]').addEventListener('click', me._ListenToDashletFormCancellation);
});
}
_ListenToDashletFormSubmission(event) {
const oDashlet = this.querySelector('ibo-dashlet[data-edit-mode="edit"]');
const sDashletId = oDashlet.GetDashletId();
if(event.detail.id === oDashlet.sType + '-turbo-stream-event' && event.detail.valid === "1") {
// Remove events
document.addEventListener('itop:TurboStreamEvent', this._ListenToDashletFormSubmission);
document.querySelector('.ibo-dashlet-panel--form-container button[name="dashboard_cancel"]').removeEventListener('click', this._ListenToDashletFormCancellation);
// Notify it all went well
CombodoToast.OpenToast('Dashlet created/updated', 'success');
// Clean edit mode
this.querySelector('ibo-dashlet[data-dashlet-id="'+sDashletId+'"]').setAttribute('data-edit-mode', 'view');
this.ShowDashletTogglers();
this.ClearDashletForm();
// Update local dashlet and refresh it
oDashlet.formData = event.detail.view_data;
this.RefreshDashlet(oDashlet);
// Re-enable dashboard buttons
this.EnableFormButtons();
}
}
_ListenToDashletFormCancellation(event) {
const oDashlet = this.querySelector('ibo-dashlet[data-edit-mode="edit"]');
const sDashletId = oDashlet.GetDashletId();
// Remove events
document.addEventListener('itop:TurboStreamEvent', this._ListenToDashletFormSubmission);
document.querySelector('.ibo-dashlet-panel--form-container button[name="dashboard_cancel"]').removeEventListener('click', this._ListenToDashletFormCancellation);
// Clean edit mode
this.querySelector('ibo-dashlet[data-dashlet-id="'+sDashletId+'"]').setAttribute('data-edit-mode', 'view');
this.ShowDashletTogglers();
this.ClearDashletForm();
// Re-enable dashboard buttons
this.EnableFormButtons();
// TODO 3.3 If this is an addition, remove the previewed dashlet
// TODO 3.3 If this is an edition, revert the dashlet to its initial state
}
CloneDashlet(sDashletId) {
this.oGrid.CloneDashlet(sDashletId);
}
RemoveDashlet(sDashletId) {
this.oGrid.RemoveDashlet(sDashletId);
}
RefreshFromBackend(bCustomDashboard = false) {
const sLoadDashboardUrl = GetAbsoluteUrlAppRoot() + `/pages/UI.php?route=dashboard.load&id=${this.sId}&custom=${bCustomDashboard ? 'true' : 'false'}`;
fetch(sLoadDashboardUrl)
.then(async oResponse => {
const oDashletData = await oResponse.json();
this.Load(oDashletData);
}
)
}
Serialize(bIncludeHtml = false) {
const sDashboardTitle = this.querySelector('.ibo-dashboard--form--inputs input[name="dashboard_title"]').value;
const sDashboardRefreshRate = this.querySelector('.ibo-dashboard--form--inputs select[name="refresh_interval"]').value;
const aSerializedGrid = this.oGrid.Serialize(bIncludeHtml);
return {
schema_version: this.schemaVersion,
id: this.sId,
title: sDashboardTitle,
refresh: sDashboardRefreshRate,
pos_dashlets: aSerializedGrid,
_token: ":)"
};
}
Save() {
// This payload shape is expected by the server
const aPayload = this.Serialize();
let sSaveUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.save&values='+encodeURIComponent(JSON.stringify(aPayload));
fetch(sSaveUrl)
.then(async data => {
const res = await data.json();
if(res.status === 'ok') {
CombodoToast.OpenToast(res.message, 'success');
this.aLastSavedState = this.Serialize(true);
this.SetEditMode(false);
} else {
CombodoToast.OpenToast(res.message, 'error');
}
})
}
Load(aSaveState) {
try {
// Validate schema version
if (aSaveState.schema_version !== this.schemaVersion) {
CombodoToast.OpenToast('Somehow, we got an incompatible dashboard schema version.', 'error');
return false;
}
// Update dashboard data
this.sId = aSaveState.id;
this.sTitle = aSaveState.title || "";
this.iRefreshRate = parseInt(aSaveState.refresh, 10) || 0;
// Update form inputs if they exist
const oTitleInput = this.querySelector('.ibo-dashboard--form--inputs input[name="dashboard_title"]');
if (oTitleInput) {
oTitleInput.value = this.sTitle;
}
const oRefreshSelect = this.querySelector('.ibo-dashboard--form--inputs select[name="refresh_interval"]');
if (oRefreshSelect) {
oRefreshSelect.value = aSaveState.refresh;
}
// Clear existing grid
this.ClearGrid();
// Load dashlets
const aDashletSlots = aSaveState.pos_dashlets || {};
for (const [sDashletId, aDashletData] of Object.entries(aDashletSlots)) {
const iPosX = aDashletData.position_x;
const iPosY = aDashletData.position_y;
const iWidth = aDashletData.width;
const iHeight = aDashletData.height;
const aDashlet = aDashletData.dashlet;
// We store the dashlet component in the HTML, not only the rendered dashlet
const sDashetHtml = aDashlet.html;
// Add dashlet to grid with its position and size
this.oGrid.AddDashlet(sDashetHtml, {
x: iPosX,
y: iPosY,
w: iWidth,
h: iHeight,
autoPosition: false
});
}
// Update last saved state
this.aLastSavedState = aSaveState;
return true;
} catch (error) {
console.error('Error loading dashboard state:', error);
CombodoToast.OpenToast('Error loading dashboard state', 'error');
return false;
}
}
ClearGrid() {
this.oGrid.ClearGrid();
}
DisplayError(sMessage, sSeverity = 'error') {
// TODO 3.3: Make this real
this.setAttribute("data-edit-mode", "error");
}
}
customElements.define('ibo-dashboard', IboDashboard);

View File

@@ -0,0 +1,68 @@
class IboDashlet extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
/** @type {string} */
this.sDashletId = this.GetDashletId();
/** @type {string} */
this.sType = this.GetDashletType();
/** @type {Object} */
this.formData = this.GetFormData();
/** @type {Object} unused yet */
this.meta = {};
this.BindEvents();
}
BindEvents() {
// Bind any dashlet-specific events here
this.querySelector('.ibo-dashlet--actions [data-role="ibo-dashlet-edit"]')?.addEventListener('click', (e) => {
this.closest('ibo-dashboard')?.EditDashlet(this.sDashletId);
});
this.querySelector('.ibo-dashlet--actions [data-role="ibo-dashlet-clone"]')?.addEventListener('click', (e) => {
this.closest('ibo-dashboard')?.CloneDashlet(this.sDashletId);
});
this.querySelector('.ibo-dashlet--actions [data-role="ibo-dashlet-remove"]')?.addEventListener('click', (e) => {
this.closest('ibo-dashboard')?.RemoveDashlet(this.sDashletId);
});
}
GetDashletId() {
return this.getAttribute('data-dashlet-id');
}
GetDashletType() {
return this.getAttribute("data-dashlet-type") || "";
}
GetFormData() {
return this.getAttribute("data-form-view-data") || "";
}
static MakeNew(sDashlet) {
const oDashlet = document.createElement('ibo-dashlet');
oDashlet.innerHTML = sDashlet;
return oDashlet;
}
Serialize(bIncludeHtml = false) {
// TODO 3.3 Should we use getters ?
let aDashletData = {
id: this.sDashletId,
type: this.sType,
properties: JSON.parse(this.formData),
};
if(bIncludeHtml) {
aDashletData.html = this.outerHTML;
}
return aDashletData;
}
}
customElements.define('ibo-dashlet', IboDashlet);

View File

@@ -14,10 +14,7 @@ if (PHP_VERSION_ID < 50600) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
throw new RuntimeException($err);
}
require_once __DIR__ . '/composer/autoload_real.php';

View File

@@ -26,12 +26,23 @@ use Composer\Semver\VersionParser;
*/
class InstalledVersions
{
/**
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
* @internal
*/
private static $selfDir = null;
/**
* @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
*/
@@ -309,6 +320,24 @@ class InstalledVersions
{
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 string
*/
private static function getSelfDir()
{
if (self::$selfDir === null) {
self::$selfDir = strtr(__DIR__, '\\', '/');
}
return self::$selfDir;
}
/**
@@ -325,7 +354,9 @@ class InstalledVersions
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = self::getSelfDir();
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')) {
@@ -333,11 +364,14 @@ class InstalledVersions
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
self::$installed = $required;
$copiedLocalDir = true;
self::$installedIsLocalDir = true;
}
}
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
$copiedLocalDir = true;
}
}
}

View File

@@ -130,6 +130,27 @@ return array(
'CheckableExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
'Collator' => $vendorDir . '/symfony/polyfill-intl-icu/Resources/stubs/Collator.php',
'Combodo\\iTop\\Application\\Branding' => $baseDir . '/sources/Application/Branding.php',
'Combodo\\iTop\\Application\\Dashboard\\Controller\\DashboardController' => $baseDir . '/sources/Application/Dashboard/Controller/DashboardController.php',
'Combodo\\iTop\\Application\\Dashboard\\DashboardException' => $baseDir . '/sources/Application/Dashboard/DashboardException.php',
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashboardFormBlock' => $baseDir . '/sources/Application/Dashboard/FormBlock/DashboardFormBlock.php',
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashletFormBlock' => $baseDir . '/sources/Application/Dashboard/FormBlock/DashletFormBlock.php',
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashletPropertiesFormBlock' => $baseDir . '/sources/Application/Dashboard/FormBlock/DashletPropertiesFormBlock.php',
'Combodo\\iTop\\Application\\Dashboard\\Layout\\DashboardLayoutGrid' => $baseDir . '/sources/Application/Dashboard/Layout/DashboardLayoutGrid.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletBadge' => $baseDir . '/sources/Application/Dashlet/Core/DashletBadge.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupBy' => $baseDir . '/sources/Application/Dashlet/Core/DashletGroupBy.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByBars' => $baseDir . '/sources/Application/Dashlet/Core/DashletGroupByBars.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByPie' => $baseDir . '/sources/Application/Dashlet/Core/DashletGroupByPie.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByTable' => $baseDir . '/sources/Application/Dashlet/Core/DashletGroupByTable.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletHeaderDynamic' => $baseDir . '/sources/Application/Dashlet/Core/DashletHeaderDynamic.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletHeaderStatic' => $baseDir . '/sources/Application/Dashlet/Core/DashletHeaderStatic.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletObjectList' => $baseDir . '/sources/Application/Dashlet/Core/DashletObjectList.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletPlainText' => $baseDir . '/sources/Application/Dashlet/Core/DashletPlainText.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletProxy' => $baseDir . '/sources/Application/Dashlet/Core/DashletProxy.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletUnknown' => $baseDir . '/sources/Application/Dashlet/Core/DashletUnknown.php',
'Combodo\\iTop\\Application\\Dashlet\\Dashlet' => $baseDir . '/sources/Application/Dashlet/Dashlet.php',
'Combodo\\iTop\\Application\\Dashlet\\DashletException' => $baseDir . '/sources/Application/Dashlet/DashletException.php',
'Combodo\\iTop\\Application\\Dashlet\\DashletFactory' => $baseDir . '/sources/Application/Dashlet/DashletFactory.php',
'Combodo\\iTop\\Application\\Dashlet\\Service\\DashletService' => $baseDir . '/sources/Application/Dashlet/Service/DashletService.php',
'Combodo\\iTop\\Application\\EventRegister\\ApplicationEvents' => $baseDir . '/sources/Application/EventRegister/ApplicationEvents.php',
'Combodo\\iTop\\Application\\Helper\\CKEditorHelper' => $baseDir . '/sources/Application/Helper/CKEditorHelper.php',
'Combodo\\iTop\\Application\\Helper\\ExportHelper' => $baseDir . '/sources/Application/Helper/ExportHelper.php',
@@ -170,6 +191,7 @@ return array(
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletFactory' => $baseDir . '/sources/Application/UI/Base/Component/Dashlet/DashletFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletHeaderStatic' => $baseDir . '/sources/Application/UI/Base/Component/Dashlet/DashletHeaderStatic.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletPlainText' => $baseDir . '/sources/Application/UI/Base/Component/Dashlet/DashletPlainText.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletWrapper' => $baseDir . '/sources/Application/UI/Base/Component/Dashlet/DashletWrapper.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTable' => $baseDir . '/sources/Application/UI/Base/Component/DataTable/DataTable.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTableConfig\\DataTableConfig' => $baseDir . '/sources/Application/UI/Base/Component/DataTable/DataTableConfig/DataTableConfig.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTableSettings' => $baseDir . '/sources/Application/UI/Base/Component/DataTable/DataTableSettings.php',
@@ -244,6 +266,10 @@ return array(
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarSpacer\\ToolbarSpacer' => $baseDir . '/sources/Application/UI/Base/Component/Toolbar/ToolbarSpacer/ToolbarSpacer.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarSpacer\\ToolbarSpacerUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/Toolbar/ToolbarSpacer/ToolbarSpacerUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/Toolbar/ToolbarUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboForm\\TurboForm' => $baseDir . '/sources/Application/UI/Base/Component/TurboForm/TurboForm.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboForm\\TurboFormUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/TurboForm/TurboFormUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboUpdate\\TurboStream' => $baseDir . '/sources/Application/UI/Base/Component/TurboStream/TurboStream.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboUpdate\\TurboStreamUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/TurboStream/TurboStreamUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntry' => $baseDir . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/ActivityEntry.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntryFactory' => $baseDir . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/ActivityEntryFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\CMDBChangeOp\\CMDBChangeOpAttachmentAddedFactory' => $baseDir . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/CMDBChangeOp/CMDBChangeOpAttachmentAddedFactory.php',
@@ -266,8 +292,13 @@ return array(
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryForm\\CaseLogEntryForm' => $baseDir . '/sources/Application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryForm.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryForm\\CaseLogEntryFormFactory' => $baseDir . '/sources/Application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryFormFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardColumn' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardColumn.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardGrid' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardGrid.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardGridSlot' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardGridSlot.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardLayout' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardLayout.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardRow' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardRow.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletEntry' => $baseDir . '/sources/Application/UI/Base/Layout/DashletPanel/DashletEntry.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletPanel' => $baseDir . '/sources/Application/UI/Base/Layout/DashletPanel/DashletPanel.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletPanelFactory' => $baseDir . '/sources/Application/UI/Base/Layout/DashletPanel/DashletPanelFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\Column' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/Column/Column.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\ColumnUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/Column/ColumnUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\MultiColumn' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/MultiColumn.php',
@@ -341,6 +372,7 @@ return array(
'Combodo\\iTop\\Controller\\AjaxRenderController' => $baseDir . '/sources/Controller/AjaxRenderController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ActivityPanelController' => $baseDir . '/sources/Controller/Base/Layout/ActivityPanelController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ObjectController' => $baseDir . '/sources/Controller/Base/Layout/ObjectController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\OqlController' => $baseDir . '/sources/Controller/Base/Layout/OqlController.php',
'Combodo\\iTop\\Controller\\Links\\LinkSetController' => $baseDir . '/sources/Controller/Links/LinkSetController.php',
'Combodo\\iTop\\Controller\\Newsroom\\iTopNewsroomController' => $baseDir . '/sources/Controller/Newsroom/iTopNewsroomController.php',
'Combodo\\iTop\\Controller\\Notifications\\ActionController' => $baseDir . '/sources/Controller/Notifications/ActionController.php',
@@ -473,8 +505,119 @@ return array(
'Combodo\\iTop\\Form\\Validator\\MultipleChoicesValidator' => $baseDir . '/sources/Form/Validator/MultipleChoicesValidator.php',
'Combodo\\iTop\\Form\\Validator\\NotEmptyExtKeyValidator' => $baseDir . '/sources/Form/Validator/NotEmptyExtKeyValidator.php',
'Combodo\\iTop\\Form\\Validator\\SelectObjectValidator' => $baseDir . '/sources/Form/Validator/SelectObjectValidator.php',
'Combodo\\iTop\\Forms\\Block\\AbstractFormBlock' => $baseDir . '/sources/Forms/Block/AbstractFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\AbstractTypeFormBlock' => $baseDir . '/sources/Forms/Block/AbstractTypeFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\CheckboxFormBlock' => $baseDir . '/sources/Forms/Block/Base/CheckboxFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFormBlock' => $baseDir . '/sources/Forms/Block/Base/ChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFromInputsBlock' => $baseDir . '/sources/Forms/Block/Base/ChoiceFromInputsBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceImageFormBlock' => $baseDir . '/sources/Forms/Block/Base/ChoiceImageFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\CollectionBlock' => $baseDir . '/sources/Forms/Block/Base/CollectionBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\DateFormBlock' => $baseDir . '/sources/Forms/Block/Base/DateFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\DateTimeFormBlock' => $baseDir . '/sources/Forms/Block/Base/DateTimeFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\FormBlock' => $baseDir . '/sources/Forms/Block/Base/FormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\HiddenFormBlock' => $baseDir . '/sources/Forms/Block/Base/HiddenFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\IntegerFormBlock' => $baseDir . '/sources/Forms/Block/Base/IntegerFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\NumberFormBlock' => $baseDir . '/sources/Forms/Block/Base/NumberFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\PolymorphicFormBlock' => $baseDir . '/sources/Forms/Block/Base/PolymorphicFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextAreaFormBlock' => $baseDir . '/sources/Forms/Block/Base/TextAreaFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextFormBlock' => $baseDir . '/sources/Forms/Block/Base/TextFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeTypeChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeTypeChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeValueChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeValueChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\Dashlet\\AggregateFunctionFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/Dashlet/AggregateFunctionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\Dashlet\\ClassAttributeGroupByFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/Dashlet/ClassAttributeGroupByFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\LabelFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/LabelFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\OqlFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/OqlFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\AbstractExpressionFormBlock' => $baseDir . '/sources/Forms/Block/Expression/AbstractExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\BooleanExpressionFormBlock' => $baseDir . '/sources/Forms/Block/Expression/BooleanExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\NumberExpressionFormBlock' => $baseDir . '/sources/Forms/Block/Expression/NumberExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\StringExpressionFormBlock' => $baseDir . '/sources/Forms/Block/Expression/StringExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockException' => $baseDir . '/sources/Forms/Block/FormBlockException.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockHelper' => $baseDir . '/sources/Forms/Block/FormBlockHelper.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockService' => $baseDir . '/sources/Forms/Block/FormBlockService.php',
'Combodo\\iTop\\Forms\\Block\\IFormBlock' => $baseDir . '/sources/Forms/Block/IFormBlock.php',
'Combodo\\iTop\\Forms\\Controller\\FormsController' => $baseDir . '/sources/Forms/Controller/FormsController.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyHandler' => $baseDir . '/sources/Forms/FormBuilder/DependencyHandler.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyMap' => $baseDir . '/sources/Forms/FormBuilder/DependencyMap.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormBuilder' => $baseDir . '/sources/Forms/FormBuilder/FormBuilder.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormBuilderException' => $baseDir . '/sources/Forms/FormBuilder/FormBuilderException.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormHelper' => $baseDir . '/sources/Forms/FormBuilder/FormHelper.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormTypeExtension' => $baseDir . '/sources/Forms/FormBuilder/FormTypeExtension.php',
'Combodo\\iTop\\Forms\\FormBuilder\\ResolvedFormType' => $baseDir . '/sources/Forms/FormBuilder/ResolvedFormType.php',
'Combodo\\iTop\\Forms\\FormBuilder\\ResolvedFormTypeFactory' => $baseDir . '/sources/Forms/FormBuilder/ResolvedFormTypeFactory.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\ChoiceFormType' => $baseDir . '/sources/Forms/FormType/Base/ChoiceFormType.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\CollectionFormType' => $baseDir . '/sources/Forms/FormType/Base/CollectionFormType.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\FormType' => $baseDir . '/sources/Forms/FormType/Base/FormType.php',
'Combodo\\iTop\\Forms\\FormType\\DataModel\\OqlFormType' => $baseDir . '/sources/Forms/FormType/DataModel/OqlFormType.php',
'Combodo\\iTop\\Forms\\FormType\\FormTypeHelper' => $baseDir . '/sources/Forms/FormType/FormTypeHelper.php',
'Combodo\\iTop\\Forms\\Forms' => $baseDir . '/sources/Forms/Forms.php',
'Combodo\\iTop\\Forms\\FormsException' => $baseDir . '/sources/Forms/FormsException.php',
'Combodo\\iTop\\Forms\\IO\\AbstractFormIO' => $baseDir . '/sources/Forms/IO/AbstractFormIO.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\AbstractConverter' => $baseDir . '/sources/Forms/IO/Converter/AbstractConverter.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\ChoiceValueToLabelConverter' => $baseDir . '/sources/Forms/IO/Converter/ChoiceValueToLabelConverter.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\CollectionToCountConverter' => $baseDir . '/sources/Forms/IO/Converter/CollectionToCountConverter.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\OqlToClassConverter' => $baseDir . '/sources/Forms/IO/Converter/OqlToClassConverter.php',
'Combodo\\iTop\\Forms\\IO\\FormBinding' => $baseDir . '/sources/Forms/IO/FormBinding.php',
'Combodo\\iTop\\Forms\\IO\\FormBlockIOException' => $baseDir . '/sources/Forms/IO/FormBlockIOException.php',
'Combodo\\iTop\\Forms\\IO\\FormInput' => $baseDir . '/sources/Forms/IO/FormInput.php',
'Combodo\\iTop\\Forms\\IO\\FormOutput' => $baseDir . '/sources/Forms/IO/FormOutput.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AbstractIOFormat' => $baseDir . '/sources/Forms/IO/Format/AbstractIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeIOFormat' => $baseDir . '/sources/Forms/IO/Format/AttributeIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeTypeArrayIOFormat' => $baseDir . '/sources/Forms/IO/Format/AttributeTypeArrayIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeTypeIOFormat' => $baseDir . '/sources/Forms/IO/Format/AttributeTypeIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\BooleanIOFormat' => $baseDir . '/sources/Forms/IO/Format/BooleanIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\ClassIOFormat' => $baseDir . '/sources/Forms/IO/Format/ClassIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\IntegerIOFormat' => $baseDir . '/sources/Forms/IO/Format/IntegerIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\NumberIOFormat' => $baseDir . '/sources/Forms/IO/Format/NumberIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\StringIOFormat' => $baseDir . '/sources/Forms/IO/Format/StringIOFormat.php',
'Combodo\\iTop\\Forms\\Register\\IORegister' => $baseDir . '/sources/Forms/Register/IORegister.php',
'Combodo\\iTop\\Forms\\Register\\Option' => $baseDir . '/sources/Forms/Register/Option.php',
'Combodo\\iTop\\Forms\\Register\\OptionsRegister' => $baseDir . '/sources/Forms/Register/OptionsRegister.php',
'Combodo\\iTop\\Forms\\Register\\RegisterException' => $baseDir . '/sources/Forms/Register/RegisterException.php',
'Combodo\\iTop\\Forms\\Twig\\Extension\\FormCompatibilityExtension' => $baseDir . '/sources/Forms/Twig/Extension/FormCompatibilityExtension.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExist' => $baseDir . '/sources/Forms/Validator/AttributeExist.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExistValidator' => $baseDir . '/sources/Forms/Validator/AttributeExistValidator.php',
'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php',
'Combodo\\iTop\\PropertyType\\Compiler\\PropertyTypeCompiler' => $baseDir . '/sources/PropertyType/Compiler/PropertyTypeCompiler.php',
'Combodo\\iTop\\PropertyType\\Compiler\\PropertyTypeCompilerException' => $baseDir . '/sources/PropertyType/Compiler/PropertyTypeCompilerException.php',
'Combodo\\iTop\\PropertyType\\PropertyType' => $baseDir . '/sources/PropertyType/PropertyType.php',
'Combodo\\iTop\\PropertyType\\PropertyTypeDesign' => $baseDir . '/sources/PropertyType/PropertyTypeDesign.php',
'Combodo\\iTop\\PropertyType\\PropertyTypeException' => $baseDir . '/sources/PropertyType/PropertyTypeException.php',
'Combodo\\iTop\\PropertyType\\PropertyTypeFactory' => $baseDir . '/sources/PropertyType/PropertyTypeFactory.php',
'Combodo\\iTop\\PropertyType\\PropertyTypeService' => $baseDir . '/sources/PropertyType/PropertyTypeService.php',
'Combodo\\iTop\\PropertyType\\Serializer\\SerializerException' => $baseDir . '/sources/PropertyType/Serializer/SerializerException.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLEncoder' => $baseDir . '/sources/PropertyType/Serializer/XMLEncoder.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\AbstractXMLFormat' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/AbstractXMLFormat.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatCSV' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatCSV.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatCollectionWithId' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatCollectionWithId.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatFactory' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatFactory.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatFlatArray' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatFlatArray.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatValueAsId' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatValueAsId.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLNormalizer' => $baseDir . '/sources/PropertyType/Serializer/XMLNormalizer.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLSerializer' => $baseDir . '/sources/PropertyType/Serializer/XMLSerializer.php',
'Combodo\\iTop\\PropertyType\\ValueType\\AbstractValueType' => $baseDir . '/sources/PropertyType/ValueType/AbstractValueType.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\AbstractBranchValueType' => $baseDir . '/sources/PropertyType/ValueType/Branch/AbstractBranchValueType.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypeCollection' => $baseDir . '/sources/PropertyType/ValueType/Branch/ValueTypeCollection.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypePolymorphic' => $baseDir . '/sources/PropertyType/ValueType/Branch/ValueTypePolymorphic.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypePropertyTree' => $baseDir . '/sources/PropertyType/ValueType/Branch/ValueTypePropertyTree.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\AbstractLeafValueType' => $baseDir . '/sources/PropertyType/ValueType/Leaf/AbstractLeafValueType.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeAggregateFunction' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeAggregateFunction.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeBoolean' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeBoolean.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeChoice' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeChoice.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeChoiceFromInput' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeChoiceFromInput.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClass' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeClass.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttribute' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttribute.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttributeGroupBy' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttributeGroupBy.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttributeValue' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttributeValue.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeCollectionOfValues' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeCollectionOfValues.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeIcon' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeIcon.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeInteger' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeInteger.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeLabel' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeLabel.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeOQL' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeOQL.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeProfileName' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeProfileName.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeString' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeString.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeText' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeText.php',
'Combodo\\iTop\\PropertyType\\ValueType\\ValueTypeFactory' => $baseDir . '/sources/PropertyType/ValueType/ValueTypeFactory.php',
'Combodo\\iTop\\Renderer\\BlockRenderer' => $baseDir . '/sources/Renderer/BlockRenderer.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => $baseDir . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => $baseDir . '/sources/Renderer/Bootstrap/BsFormRenderer.php',
@@ -497,6 +640,8 @@ return array(
'Combodo\\iTop\\Service\\Base\\ObjectRepository' => $baseDir . '/sources/Service/Base/ObjectRepository.php',
'Combodo\\iTop\\Service\\Base\\iDataPostProcessor' => $baseDir . '/sources/Service/Base/iDataPostProcessor.php',
'Combodo\\iTop\\Service\\Cache\\DataModelDependantCache' => $baseDir . '/sources/Service/Cache/DataModelDependantCache.php',
'Combodo\\iTop\\Service\\DependencyInjection\\DIException' => $baseDir . '/sources/Service/DependencyInjection/DIException.php',
'Combodo\\iTop\\Service\\DependencyInjection\\ServiceLocator' => $baseDir . '/sources/Service/DependencyInjection/ServiceLocator.php',
'Combodo\\iTop\\Service\\Events\\Description\\EventDataDescription' => $baseDir . '/sources/Service/Events/Description/EventDataDescription.php',
'Combodo\\iTop\\Service\\Events\\Description\\EventDescription' => $baseDir . '/sources/Service/Events/Description/EventDescription.php',
'Combodo\\iTop\\Service\\Events\\EventData' => $baseDir . '/sources/Service/Events/EventData.php',
@@ -564,19 +709,6 @@ return array(
'DashboardLayoutThreeCols' => $baseDir . '/application/dashboardlayout.class.inc.php',
'DashboardLayoutTwoCols' => $baseDir . '/application/dashboardlayout.class.inc.php',
'DashboardMenuNode' => $baseDir . '/application/menunode.class.inc.php',
'Dashlet' => $baseDir . '/application/dashlet.class.inc.php',
'DashletBadge' => $baseDir . '/application/dashlet.class.inc.php',
'DashletEmptyCell' => $baseDir . '/application/dashlet.class.inc.php',
'DashletGroupBy' => $baseDir . '/application/dashlet.class.inc.php',
'DashletGroupByBars' => $baseDir . '/application/dashlet.class.inc.php',
'DashletGroupByPie' => $baseDir . '/application/dashlet.class.inc.php',
'DashletGroupByTable' => $baseDir . '/application/dashlet.class.inc.php',
'DashletHeaderDynamic' => $baseDir . '/application/dashlet.class.inc.php',
'DashletHeaderStatic' => $baseDir . '/application/dashlet.class.inc.php',
'DashletObjectList' => $baseDir . '/application/dashlet.class.inc.php',
'DashletPlainText' => $baseDir . '/application/dashlet.class.inc.php',
'DashletProxy' => $baseDir . '/application/dashlet.class.inc.php',
'DashletUnknown' => $baseDir . '/application/dashlet.class.inc.php',
'Datamatrix' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php',
'DateError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
'DateException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
@@ -3071,6 +3203,227 @@ return array(
'Symfony\\Component\\String\\Slugger\\AsciiSlugger' => $vendorDir . '/symfony/string/Slugger/AsciiSlugger.php',
'Symfony\\Component\\String\\Slugger\\SluggerInterface' => $vendorDir . '/symfony/string/Slugger/SluggerInterface.php',
'Symfony\\Component\\String\\UnicodeString' => $vendorDir . '/symfony/string/UnicodeString.php',
'Symfony\\Component\\Validator\\Attribute\\HasNamedArguments' => $vendorDir . '/symfony/validator/Attribute/HasNamedArguments.php',
'Symfony\\Component\\Validator\\Command\\DebugCommand' => $vendorDir . '/symfony/validator/Command/DebugCommand.php',
'Symfony\\Component\\Validator\\Constraint' => $vendorDir . '/symfony/validator/Constraint.php',
'Symfony\\Component\\Validator\\ConstraintValidator' => $vendorDir . '/symfony/validator/ConstraintValidator.php',
'Symfony\\Component\\Validator\\ConstraintValidatorFactory' => $vendorDir . '/symfony/validator/ConstraintValidatorFactory.php',
'Symfony\\Component\\Validator\\ConstraintValidatorFactoryInterface' => $vendorDir . '/symfony/validator/ConstraintValidatorFactoryInterface.php',
'Symfony\\Component\\Validator\\ConstraintValidatorInterface' => $vendorDir . '/symfony/validator/ConstraintValidatorInterface.php',
'Symfony\\Component\\Validator\\ConstraintViolation' => $vendorDir . '/symfony/validator/ConstraintViolation.php',
'Symfony\\Component\\Validator\\ConstraintViolationInterface' => $vendorDir . '/symfony/validator/ConstraintViolationInterface.php',
'Symfony\\Component\\Validator\\ConstraintViolationList' => $vendorDir . '/symfony/validator/ConstraintViolationList.php',
'Symfony\\Component\\Validator\\ConstraintViolationListInterface' => $vendorDir . '/symfony/validator/ConstraintViolationListInterface.php',
'Symfony\\Component\\Validator\\Constraints\\AbstractComparison' => $vendorDir . '/symfony/validator/Constraints/AbstractComparison.php',
'Symfony\\Component\\Validator\\Constraints\\AbstractComparisonValidator' => $vendorDir . '/symfony/validator/Constraints/AbstractComparisonValidator.php',
'Symfony\\Component\\Validator\\Constraints\\All' => $vendorDir . '/symfony/validator/Constraints/All.php',
'Symfony\\Component\\Validator\\Constraints\\AllValidator' => $vendorDir . '/symfony/validator/Constraints/AllValidator.php',
'Symfony\\Component\\Validator\\Constraints\\AtLeastOneOf' => $vendorDir . '/symfony/validator/Constraints/AtLeastOneOf.php',
'Symfony\\Component\\Validator\\Constraints\\AtLeastOneOfValidator' => $vendorDir . '/symfony/validator/Constraints/AtLeastOneOfValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Bic' => $vendorDir . '/symfony/validator/Constraints/Bic.php',
'Symfony\\Component\\Validator\\Constraints\\BicValidator' => $vendorDir . '/symfony/validator/Constraints/BicValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Blank' => $vendorDir . '/symfony/validator/Constraints/Blank.php',
'Symfony\\Component\\Validator\\Constraints\\BlankValidator' => $vendorDir . '/symfony/validator/Constraints/BlankValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Callback' => $vendorDir . '/symfony/validator/Constraints/Callback.php',
'Symfony\\Component\\Validator\\Constraints\\CallbackValidator' => $vendorDir . '/symfony/validator/Constraints/CallbackValidator.php',
'Symfony\\Component\\Validator\\Constraints\\CardScheme' => $vendorDir . '/symfony/validator/Constraints/CardScheme.php',
'Symfony\\Component\\Validator\\Constraints\\CardSchemeValidator' => $vendorDir . '/symfony/validator/Constraints/CardSchemeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Cascade' => $vendorDir . '/symfony/validator/Constraints/Cascade.php',
'Symfony\\Component\\Validator\\Constraints\\Choice' => $vendorDir . '/symfony/validator/Constraints/Choice.php',
'Symfony\\Component\\Validator\\Constraints\\ChoiceValidator' => $vendorDir . '/symfony/validator/Constraints/ChoiceValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Cidr' => $vendorDir . '/symfony/validator/Constraints/Cidr.php',
'Symfony\\Component\\Validator\\Constraints\\CidrValidator' => $vendorDir . '/symfony/validator/Constraints/CidrValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Collection' => $vendorDir . '/symfony/validator/Constraints/Collection.php',
'Symfony\\Component\\Validator\\Constraints\\CollectionValidator' => $vendorDir . '/symfony/validator/Constraints/CollectionValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Composite' => $vendorDir . '/symfony/validator/Constraints/Composite.php',
'Symfony\\Component\\Validator\\Constraints\\Compound' => $vendorDir . '/symfony/validator/Constraints/Compound.php',
'Symfony\\Component\\Validator\\Constraints\\CompoundValidator' => $vendorDir . '/symfony/validator/Constraints/CompoundValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Count' => $vendorDir . '/symfony/validator/Constraints/Count.php',
'Symfony\\Component\\Validator\\Constraints\\CountValidator' => $vendorDir . '/symfony/validator/Constraints/CountValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Country' => $vendorDir . '/symfony/validator/Constraints/Country.php',
'Symfony\\Component\\Validator\\Constraints\\CountryValidator' => $vendorDir . '/symfony/validator/Constraints/CountryValidator.php',
'Symfony\\Component\\Validator\\Constraints\\CssColor' => $vendorDir . '/symfony/validator/Constraints/CssColor.php',
'Symfony\\Component\\Validator\\Constraints\\CssColorValidator' => $vendorDir . '/symfony/validator/Constraints/CssColorValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Currency' => $vendorDir . '/symfony/validator/Constraints/Currency.php',
'Symfony\\Component\\Validator\\Constraints\\CurrencyValidator' => $vendorDir . '/symfony/validator/Constraints/CurrencyValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Date' => $vendorDir . '/symfony/validator/Constraints/Date.php',
'Symfony\\Component\\Validator\\Constraints\\DateTime' => $vendorDir . '/symfony/validator/Constraints/DateTime.php',
'Symfony\\Component\\Validator\\Constraints\\DateTimeValidator' => $vendorDir . '/symfony/validator/Constraints/DateTimeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\DateValidator' => $vendorDir . '/symfony/validator/Constraints/DateValidator.php',
'Symfony\\Component\\Validator\\Constraints\\DisableAutoMapping' => $vendorDir . '/symfony/validator/Constraints/DisableAutoMapping.php',
'Symfony\\Component\\Validator\\Constraints\\DivisibleBy' => $vendorDir . '/symfony/validator/Constraints/DivisibleBy.php',
'Symfony\\Component\\Validator\\Constraints\\DivisibleByValidator' => $vendorDir . '/symfony/validator/Constraints/DivisibleByValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Email' => $vendorDir . '/symfony/validator/Constraints/Email.php',
'Symfony\\Component\\Validator\\Constraints\\EmailValidator' => $vendorDir . '/symfony/validator/Constraints/EmailValidator.php',
'Symfony\\Component\\Validator\\Constraints\\EnableAutoMapping' => $vendorDir . '/symfony/validator/Constraints/EnableAutoMapping.php',
'Symfony\\Component\\Validator\\Constraints\\EqualTo' => $vendorDir . '/symfony/validator/Constraints/EqualTo.php',
'Symfony\\Component\\Validator\\Constraints\\EqualToValidator' => $vendorDir . '/symfony/validator/Constraints/EqualToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Existence' => $vendorDir . '/symfony/validator/Constraints/Existence.php',
'Symfony\\Component\\Validator\\Constraints\\Expression' => $vendorDir . '/symfony/validator/Constraints/Expression.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageProvider' => $vendorDir . '/symfony/validator/Constraints/ExpressionLanguageProvider.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntax' => $vendorDir . '/symfony/validator/Constraints/ExpressionLanguageSyntax.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntaxValidator' => $vendorDir . '/symfony/validator/Constraints/ExpressionLanguageSyntaxValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionSyntax' => $vendorDir . '/symfony/validator/Constraints/ExpressionSyntax.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionSyntaxValidator' => $vendorDir . '/symfony/validator/Constraints/ExpressionSyntaxValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionValidator' => $vendorDir . '/symfony/validator/Constraints/ExpressionValidator.php',
'Symfony\\Component\\Validator\\Constraints\\File' => $vendorDir . '/symfony/validator/Constraints/File.php',
'Symfony\\Component\\Validator\\Constraints\\FileValidator' => $vendorDir . '/symfony/validator/Constraints/FileValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThan' => $vendorDir . '/symfony/validator/Constraints/GreaterThan.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqual' => $vendorDir . '/symfony/validator/Constraints/GreaterThanOrEqual.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqualValidator' => $vendorDir . '/symfony/validator/Constraints/GreaterThanOrEqualValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanValidator' => $vendorDir . '/symfony/validator/Constraints/GreaterThanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GroupSequence' => $vendorDir . '/symfony/validator/Constraints/GroupSequence.php',
'Symfony\\Component\\Validator\\Constraints\\GroupSequenceProvider' => $vendorDir . '/symfony/validator/Constraints/GroupSequenceProvider.php',
'Symfony\\Component\\Validator\\Constraints\\Hostname' => $vendorDir . '/symfony/validator/Constraints/Hostname.php',
'Symfony\\Component\\Validator\\Constraints\\HostnameValidator' => $vendorDir . '/symfony/validator/Constraints/HostnameValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Iban' => $vendorDir . '/symfony/validator/Constraints/Iban.php',
'Symfony\\Component\\Validator\\Constraints\\IbanValidator' => $vendorDir . '/symfony/validator/Constraints/IbanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IdenticalTo' => $vendorDir . '/symfony/validator/Constraints/IdenticalTo.php',
'Symfony\\Component\\Validator\\Constraints\\IdenticalToValidator' => $vendorDir . '/symfony/validator/Constraints/IdenticalToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Image' => $vendorDir . '/symfony/validator/Constraints/Image.php',
'Symfony\\Component\\Validator\\Constraints\\ImageValidator' => $vendorDir . '/symfony/validator/Constraints/ImageValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Ip' => $vendorDir . '/symfony/validator/Constraints/Ip.php',
'Symfony\\Component\\Validator\\Constraints\\IpValidator' => $vendorDir . '/symfony/validator/Constraints/IpValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsFalse' => $vendorDir . '/symfony/validator/Constraints/IsFalse.php',
'Symfony\\Component\\Validator\\Constraints\\IsFalseValidator' => $vendorDir . '/symfony/validator/Constraints/IsFalseValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsNull' => $vendorDir . '/symfony/validator/Constraints/IsNull.php',
'Symfony\\Component\\Validator\\Constraints\\IsNullValidator' => $vendorDir . '/symfony/validator/Constraints/IsNullValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsTrue' => $vendorDir . '/symfony/validator/Constraints/IsTrue.php',
'Symfony\\Component\\Validator\\Constraints\\IsTrueValidator' => $vendorDir . '/symfony/validator/Constraints/IsTrueValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Isbn' => $vendorDir . '/symfony/validator/Constraints/Isbn.php',
'Symfony\\Component\\Validator\\Constraints\\IsbnValidator' => $vendorDir . '/symfony/validator/Constraints/IsbnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Isin' => $vendorDir . '/symfony/validator/Constraints/Isin.php',
'Symfony\\Component\\Validator\\Constraints\\IsinValidator' => $vendorDir . '/symfony/validator/Constraints/IsinValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Issn' => $vendorDir . '/symfony/validator/Constraints/Issn.php',
'Symfony\\Component\\Validator\\Constraints\\IssnValidator' => $vendorDir . '/symfony/validator/Constraints/IssnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Json' => $vendorDir . '/symfony/validator/Constraints/Json.php',
'Symfony\\Component\\Validator\\Constraints\\JsonValidator' => $vendorDir . '/symfony/validator/Constraints/JsonValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Language' => $vendorDir . '/symfony/validator/Constraints/Language.php',
'Symfony\\Component\\Validator\\Constraints\\LanguageValidator' => $vendorDir . '/symfony/validator/Constraints/LanguageValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Length' => $vendorDir . '/symfony/validator/Constraints/Length.php',
'Symfony\\Component\\Validator\\Constraints\\LengthValidator' => $vendorDir . '/symfony/validator/Constraints/LengthValidator.php',
'Symfony\\Component\\Validator\\Constraints\\LessThan' => $vendorDir . '/symfony/validator/Constraints/LessThan.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanOrEqual' => $vendorDir . '/symfony/validator/Constraints/LessThanOrEqual.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanOrEqualValidator' => $vendorDir . '/symfony/validator/Constraints/LessThanOrEqualValidator.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanValidator' => $vendorDir . '/symfony/validator/Constraints/LessThanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Locale' => $vendorDir . '/symfony/validator/Constraints/Locale.php',
'Symfony\\Component\\Validator\\Constraints\\LocaleValidator' => $vendorDir . '/symfony/validator/Constraints/LocaleValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Luhn' => $vendorDir . '/symfony/validator/Constraints/Luhn.php',
'Symfony\\Component\\Validator\\Constraints\\LuhnValidator' => $vendorDir . '/symfony/validator/Constraints/LuhnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Negative' => $vendorDir . '/symfony/validator/Constraints/Negative.php',
'Symfony\\Component\\Validator\\Constraints\\NegativeOrZero' => $vendorDir . '/symfony/validator/Constraints/NegativeOrZero.php',
'Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharacters' => $vendorDir . '/symfony/validator/Constraints/NoSuspiciousCharacters.php',
'Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharactersValidator' => $vendorDir . '/symfony/validator/Constraints/NoSuspiciousCharactersValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotBlank' => $vendorDir . '/symfony/validator/Constraints/NotBlank.php',
'Symfony\\Component\\Validator\\Constraints\\NotBlankValidator' => $vendorDir . '/symfony/validator/Constraints/NotBlankValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotCompromisedPassword' => $vendorDir . '/symfony/validator/Constraints/NotCompromisedPassword.php',
'Symfony\\Component\\Validator\\Constraints\\NotCompromisedPasswordValidator' => $vendorDir . '/symfony/validator/Constraints/NotCompromisedPasswordValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotEqualTo' => $vendorDir . '/symfony/validator/Constraints/NotEqualTo.php',
'Symfony\\Component\\Validator\\Constraints\\NotEqualToValidator' => $vendorDir . '/symfony/validator/Constraints/NotEqualToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotIdenticalTo' => $vendorDir . '/symfony/validator/Constraints/NotIdenticalTo.php',
'Symfony\\Component\\Validator\\Constraints\\NotIdenticalToValidator' => $vendorDir . '/symfony/validator/Constraints/NotIdenticalToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotNull' => $vendorDir . '/symfony/validator/Constraints/NotNull.php',
'Symfony\\Component\\Validator\\Constraints\\NotNullValidator' => $vendorDir . '/symfony/validator/Constraints/NotNullValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Optional' => $vendorDir . '/symfony/validator/Constraints/Optional.php',
'Symfony\\Component\\Validator\\Constraints\\PasswordStrength' => $vendorDir . '/symfony/validator/Constraints/PasswordStrength.php',
'Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator' => $vendorDir . '/symfony/validator/Constraints/PasswordStrengthValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Positive' => $vendorDir . '/symfony/validator/Constraints/Positive.php',
'Symfony\\Component\\Validator\\Constraints\\PositiveOrZero' => $vendorDir . '/symfony/validator/Constraints/PositiveOrZero.php',
'Symfony\\Component\\Validator\\Constraints\\Range' => $vendorDir . '/symfony/validator/Constraints/Range.php',
'Symfony\\Component\\Validator\\Constraints\\RangeValidator' => $vendorDir . '/symfony/validator/Constraints/RangeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Regex' => $vendorDir . '/symfony/validator/Constraints/Regex.php',
'Symfony\\Component\\Validator\\Constraints\\RegexValidator' => $vendorDir . '/symfony/validator/Constraints/RegexValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Required' => $vendorDir . '/symfony/validator/Constraints/Required.php',
'Symfony\\Component\\Validator\\Constraints\\Sequentially' => $vendorDir . '/symfony/validator/Constraints/Sequentially.php',
'Symfony\\Component\\Validator\\Constraints\\SequentiallyValidator' => $vendorDir . '/symfony/validator/Constraints/SequentiallyValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Time' => $vendorDir . '/symfony/validator/Constraints/Time.php',
'Symfony\\Component\\Validator\\Constraints\\TimeValidator' => $vendorDir . '/symfony/validator/Constraints/TimeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Timezone' => $vendorDir . '/symfony/validator/Constraints/Timezone.php',
'Symfony\\Component\\Validator\\Constraints\\TimezoneValidator' => $vendorDir . '/symfony/validator/Constraints/TimezoneValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Traverse' => $vendorDir . '/symfony/validator/Constraints/Traverse.php',
'Symfony\\Component\\Validator\\Constraints\\Type' => $vendorDir . '/symfony/validator/Constraints/Type.php',
'Symfony\\Component\\Validator\\Constraints\\TypeValidator' => $vendorDir . '/symfony/validator/Constraints/TypeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Ulid' => $vendorDir . '/symfony/validator/Constraints/Ulid.php',
'Symfony\\Component\\Validator\\Constraints\\UlidValidator' => $vendorDir . '/symfony/validator/Constraints/UlidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Unique' => $vendorDir . '/symfony/validator/Constraints/Unique.php',
'Symfony\\Component\\Validator\\Constraints\\UniqueValidator' => $vendorDir . '/symfony/validator/Constraints/UniqueValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Url' => $vendorDir . '/symfony/validator/Constraints/Url.php',
'Symfony\\Component\\Validator\\Constraints\\UrlValidator' => $vendorDir . '/symfony/validator/Constraints/UrlValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Uuid' => $vendorDir . '/symfony/validator/Constraints/Uuid.php',
'Symfony\\Component\\Validator\\Constraints\\UuidValidator' => $vendorDir . '/symfony/validator/Constraints/UuidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Valid' => $vendorDir . '/symfony/validator/Constraints/Valid.php',
'Symfony\\Component\\Validator\\Constraints\\ValidValidator' => $vendorDir . '/symfony/validator/Constraints/ValidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\When' => $vendorDir . '/symfony/validator/Constraints/When.php',
'Symfony\\Component\\Validator\\Constraints\\WhenValidator' => $vendorDir . '/symfony/validator/Constraints/WhenValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ZeroComparisonConstraintTrait' => $vendorDir . '/symfony/validator/Constraints/ZeroComparisonConstraintTrait.php',
'Symfony\\Component\\Validator\\ContainerConstraintValidatorFactory' => $vendorDir . '/symfony/validator/ContainerConstraintValidatorFactory.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContext' => $vendorDir . '/symfony/validator/Context/ExecutionContext.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextFactory' => $vendorDir . '/symfony/validator/Context/ExecutionContextFactory.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextFactoryInterface' => $vendorDir . '/symfony/validator/Context/ExecutionContextFactoryInterface.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextInterface' => $vendorDir . '/symfony/validator/Context/ExecutionContextInterface.php',
'Symfony\\Component\\Validator\\DataCollector\\ValidatorDataCollector' => $vendorDir . '/symfony/validator/DataCollector/ValidatorDataCollector.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddAutoMappingConfigurationPass' => $vendorDir . '/symfony/validator/DependencyInjection/AddAutoMappingConfigurationPass.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddConstraintValidatorsPass' => $vendorDir . '/symfony/validator/DependencyInjection/AddConstraintValidatorsPass.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddValidatorInitializersPass' => $vendorDir . '/symfony/validator/DependencyInjection/AddValidatorInitializersPass.php',
'Symfony\\Component\\Validator\\Exception\\BadMethodCallException' => $vendorDir . '/symfony/validator/Exception/BadMethodCallException.php',
'Symfony\\Component\\Validator\\Exception\\ConstraintDefinitionException' => $vendorDir . '/symfony/validator/Exception/ConstraintDefinitionException.php',
'Symfony\\Component\\Validator\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/validator/Exception/ExceptionInterface.php',
'Symfony\\Component\\Validator\\Exception\\GroupDefinitionException' => $vendorDir . '/symfony/validator/Exception/GroupDefinitionException.php',
'Symfony\\Component\\Validator\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/validator/Exception/InvalidArgumentException.php',
'Symfony\\Component\\Validator\\Exception\\InvalidOptionsException' => $vendorDir . '/symfony/validator/Exception/InvalidOptionsException.php',
'Symfony\\Component\\Validator\\Exception\\LogicException' => $vendorDir . '/symfony/validator/Exception/LogicException.php',
'Symfony\\Component\\Validator\\Exception\\MappingException' => $vendorDir . '/symfony/validator/Exception/MappingException.php',
'Symfony\\Component\\Validator\\Exception\\MissingOptionsException' => $vendorDir . '/symfony/validator/Exception/MissingOptionsException.php',
'Symfony\\Component\\Validator\\Exception\\NoSuchMetadataException' => $vendorDir . '/symfony/validator/Exception/NoSuchMetadataException.php',
'Symfony\\Component\\Validator\\Exception\\OutOfBoundsException' => $vendorDir . '/symfony/validator/Exception/OutOfBoundsException.php',
'Symfony\\Component\\Validator\\Exception\\RuntimeException' => $vendorDir . '/symfony/validator/Exception/RuntimeException.php',
'Symfony\\Component\\Validator\\Exception\\UnexpectedTypeException' => $vendorDir . '/symfony/validator/Exception/UnexpectedTypeException.php',
'Symfony\\Component\\Validator\\Exception\\UnexpectedValueException' => $vendorDir . '/symfony/validator/Exception/UnexpectedValueException.php',
'Symfony\\Component\\Validator\\Exception\\UnsupportedMetadataException' => $vendorDir . '/symfony/validator/Exception/UnsupportedMetadataException.php',
'Symfony\\Component\\Validator\\Exception\\ValidationFailedException' => $vendorDir . '/symfony/validator/Exception/ValidationFailedException.php',
'Symfony\\Component\\Validator\\Exception\\ValidatorException' => $vendorDir . '/symfony/validator/Exception/ValidatorException.php',
'Symfony\\Component\\Validator\\GroupProviderInterface' => $vendorDir . '/symfony/validator/GroupProviderInterface.php',
'Symfony\\Component\\Validator\\GroupSequenceProviderInterface' => $vendorDir . '/symfony/validator/GroupSequenceProviderInterface.php',
'Symfony\\Component\\Validator\\Mapping\\AutoMappingStrategy' => $vendorDir . '/symfony/validator/Mapping/AutoMappingStrategy.php',
'Symfony\\Component\\Validator\\Mapping\\CascadingStrategy' => $vendorDir . '/symfony/validator/Mapping/CascadingStrategy.php',
'Symfony\\Component\\Validator\\Mapping\\ClassMetadata' => $vendorDir . '/symfony/validator/Mapping/ClassMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\ClassMetadataInterface' => $vendorDir . '/symfony/validator/Mapping/ClassMetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\BlackHoleMetadataFactory' => $vendorDir . '/symfony/validator/Mapping/Factory/BlackHoleMetadataFactory.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\LazyLoadingMetadataFactory' => $vendorDir . '/symfony/validator/Mapping/Factory/LazyLoadingMetadataFactory.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\MetadataFactoryInterface' => $vendorDir . '/symfony/validator/Mapping/Factory/MetadataFactoryInterface.php',
'Symfony\\Component\\Validator\\Mapping\\GenericMetadata' => $vendorDir . '/symfony/validator/Mapping/GenericMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\GetterMetadata' => $vendorDir . '/symfony/validator/Mapping/GetterMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AbstractLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/AbstractLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AnnotationLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/AnnotationLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AttributeLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/AttributeLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AutoMappingTrait' => $vendorDir . '/symfony/validator/Mapping/Loader/AutoMappingTrait.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\FileLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/FileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\FilesLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/FilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\LoaderChain' => $vendorDir . '/symfony/validator/Mapping/Loader/LoaderChain.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\LoaderInterface' => $vendorDir . '/symfony/validator/Mapping/Loader/LoaderInterface.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\PropertyInfoLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/PropertyInfoLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\StaticMethodLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/StaticMethodLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\XmlFileLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/XmlFileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\XmlFilesLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/XmlFilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\YamlFileLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/YamlFileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\YamlFilesLoader' => $vendorDir . '/symfony/validator/Mapping/Loader/YamlFilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\MemberMetadata' => $vendorDir . '/symfony/validator/Mapping/MemberMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\MetadataInterface' => $vendorDir . '/symfony/validator/Mapping/MetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\PropertyMetadata' => $vendorDir . '/symfony/validator/Mapping/PropertyMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\PropertyMetadataInterface' => $vendorDir . '/symfony/validator/Mapping/PropertyMetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\TraversalStrategy' => $vendorDir . '/symfony/validator/Mapping/TraversalStrategy.php',
'Symfony\\Component\\Validator\\ObjectInitializerInterface' => $vendorDir . '/symfony/validator/ObjectInitializerInterface.php',
'Symfony\\Component\\Validator\\Util\\PropertyPath' => $vendorDir . '/symfony/validator/Util/PropertyPath.php',
'Symfony\\Component\\Validator\\Validation' => $vendorDir . '/symfony/validator/Validation.php',
'Symfony\\Component\\Validator\\ValidatorBuilder' => $vendorDir . '/symfony/validator/ValidatorBuilder.php',
'Symfony\\Component\\Validator\\Validator\\ContextualValidatorInterface' => $vendorDir . '/symfony/validator/Validator/ContextualValidatorInterface.php',
'Symfony\\Component\\Validator\\Validator\\LazyProperty' => $vendorDir . '/symfony/validator/Validator/LazyProperty.php',
'Symfony\\Component\\Validator\\Validator\\RecursiveContextualValidator' => $vendorDir . '/symfony/validator/Validator/RecursiveContextualValidator.php',
'Symfony\\Component\\Validator\\Validator\\RecursiveValidator' => $vendorDir . '/symfony/validator/Validator/RecursiveValidator.php',
'Symfony\\Component\\Validator\\Validator\\TraceableValidator' => $vendorDir . '/symfony/validator/Validator/TraceableValidator.php',
'Symfony\\Component\\Validator\\Validator\\ValidatorInterface' => $vendorDir . '/symfony/validator/Validator/ValidatorInterface.php',
'Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilder' => $vendorDir . '/symfony/validator/Violation/ConstraintViolationBuilder.php',
'Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilderInterface' => $vendorDir . '/symfony/validator/Violation/ConstraintViolationBuilderInterface.php',
'Symfony\\Component\\VarDumper\\Caster\\AmqpCaster' => $vendorDir . '/symfony/var-dumper/Caster/AmqpCaster.php',
'Symfony\\Component\\VarDumper\\Caster\\ArgsStub' => $vendorDir . '/symfony/var-dumper/Caster/ArgsStub.php',
'Symfony\\Component\\VarDumper\\Caster\\Caster' => $vendorDir . '/symfony/var-dumper/Caster/Caster.php',

View File

@@ -22,6 +22,7 @@ return array(
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'),
'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
'Symfony\\Component\\Validator\\' => array($vendorDir . '/symfony/validator'),
'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'),
'Symfony\\Component\\Stopwatch\\' => array($vendorDir . '/symfony/stopwatch'),
'Symfony\\Component\\Security\\Csrf\\' => array($vendorDir . '/symfony/security-csrf'),
@@ -61,7 +62,7 @@ return array(
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'),
'Pelago\\Emogrifier\\' => array($vendorDir . '/pelago/emogrifier/src'),
'League\\OAuth2\\Client\\' => array($vendorDir . '/league/oauth2-client/src', $vendorDir . '/league/oauth2-google/src'),
'League\\OAuth2\\Client\\' => array($vendorDir . '/league/oauth2-google/src', $vendorDir . '/league/oauth2-client/src'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),

View File

@@ -49,6 +49,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Symfony\\Component\\Yaml\\' => 23,
'Symfony\\Component\\VarExporter\\' => 30,
'Symfony\\Component\\VarDumper\\' => 28,
'Symfony\\Component\\Validator\\' => 28,
'Symfony\\Component\\String\\' => 25,
'Symfony\\Component\\Stopwatch\\' => 28,
'Symfony\\Component\\Security\\Csrf\\' => 32,
@@ -181,6 +182,10 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
array (
0 => __DIR__ . '/..' . '/symfony/var-dumper',
),
'Symfony\\Component\\Validator\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/validator',
),
'Symfony\\Component\\String\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/string',
@@ -340,8 +345,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
),
'League\\OAuth2\\Client\\' =>
array (
0 => __DIR__ . '/..' . '/league/oauth2-client/src',
1 => __DIR__ . '/..' . '/league/oauth2-google/src',
0 => __DIR__ . '/..' . '/league/oauth2-google/src',
1 => __DIR__ . '/..' . '/league/oauth2-client/src',
),
'GuzzleHttp\\Psr7\\' =>
array (
@@ -511,6 +516,27 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'CheckableExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
'Collator' => __DIR__ . '/..' . '/symfony/polyfill-intl-icu/Resources/stubs/Collator.php',
'Combodo\\iTop\\Application\\Branding' => __DIR__ . '/../..' . '/sources/Application/Branding.php',
'Combodo\\iTop\\Application\\Dashboard\\Controller\\DashboardController' => __DIR__ . '/../..' . '/sources/Application/Dashboard/Controller/DashboardController.php',
'Combodo\\iTop\\Application\\Dashboard\\DashboardException' => __DIR__ . '/../..' . '/sources/Application/Dashboard/DashboardException.php',
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashboardFormBlock' => __DIR__ . '/../..' . '/sources/Application/Dashboard/FormBlock/DashboardFormBlock.php',
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashletFormBlock' => __DIR__ . '/../..' . '/sources/Application/Dashboard/FormBlock/DashletFormBlock.php',
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashletPropertiesFormBlock' => __DIR__ . '/../..' . '/sources/Application/Dashboard/FormBlock/DashletPropertiesFormBlock.php',
'Combodo\\iTop\\Application\\Dashboard\\Layout\\DashboardLayoutGrid' => __DIR__ . '/../..' . '/sources/Application/Dashboard/Layout/DashboardLayoutGrid.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletBadge' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletBadge.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupBy' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletGroupBy.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByBars' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletGroupByBars.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByPie' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletGroupByPie.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByTable' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletGroupByTable.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletHeaderDynamic' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletHeaderDynamic.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletHeaderStatic' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletHeaderStatic.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletObjectList' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletObjectList.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletPlainText' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletPlainText.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletProxy' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletProxy.php',
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletUnknown' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletUnknown.php',
'Combodo\\iTop\\Application\\Dashlet\\Dashlet' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Dashlet.php',
'Combodo\\iTop\\Application\\Dashlet\\DashletException' => __DIR__ . '/../..' . '/sources/Application/Dashlet/DashletException.php',
'Combodo\\iTop\\Application\\Dashlet\\DashletFactory' => __DIR__ . '/../..' . '/sources/Application/Dashlet/DashletFactory.php',
'Combodo\\iTop\\Application\\Dashlet\\Service\\DashletService' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Service/DashletService.php',
'Combodo\\iTop\\Application\\EventRegister\\ApplicationEvents' => __DIR__ . '/../..' . '/sources/Application/EventRegister/ApplicationEvents.php',
'Combodo\\iTop\\Application\\Helper\\CKEditorHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/CKEditorHelper.php',
'Combodo\\iTop\\Application\\Helper\\ExportHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/ExportHelper.php',
@@ -551,6 +577,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Dashlet/DashletFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletHeaderStatic' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Dashlet/DashletHeaderStatic.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletPlainText' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Dashlet/DashletPlainText.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletWrapper' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Dashlet/DashletWrapper.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTable' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/DataTable/DataTable.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTableConfig\\DataTableConfig' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/DataTable/DataTableConfig/DataTableConfig.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTableSettings' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/DataTable/DataTableSettings.php',
@@ -625,6 +652,10 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarSpacer\\ToolbarSpacer' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Toolbar/ToolbarSpacer/ToolbarSpacer.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarSpacer\\ToolbarSpacerUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Toolbar/ToolbarSpacer/ToolbarSpacerUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Toolbar\\ToolbarUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Toolbar/ToolbarUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboForm\\TurboForm' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/TurboForm/TurboForm.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboForm\\TurboFormUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/TurboForm/TurboFormUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboUpdate\\TurboStream' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/TurboStream/TurboStream.php',
'Combodo\\iTop\\Application\\UI\\Base\\Component\\TurboUpdate\\TurboStreamUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/TurboStream/TurboStreamUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntry' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/ActivityEntry.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\ActivityEntryFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/ActivityEntryFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\CMDBChangeOp\\CMDBChangeOpAttachmentAddedFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/ActivityPanel/ActivityEntry/CMDBChangeOp/CMDBChangeOpAttachmentAddedFactory.php',
@@ -647,8 +678,13 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryForm\\CaseLogEntryForm' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryForm.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryForm\\CaseLogEntryFormFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryFormFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardColumn' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardColumn.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardGrid' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardGrid.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardGridSlot' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardGridSlot.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardLayout' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardLayout.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardRow' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardRow.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletEntry' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/DashletPanel/DashletEntry.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletPanel' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/DashletPanel/DashletPanel.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletPanelFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/DashletPanel/DashletPanelFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\Column' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/Column/Column.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\ColumnUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/Column/ColumnUIBlockFactory.php',
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\MultiColumn' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/MultiColumn.php',
@@ -722,6 +758,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Controller\\AjaxRenderController' => __DIR__ . '/../..' . '/sources/Controller/AjaxRenderController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ActivityPanelController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/ActivityPanelController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ObjectController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/ObjectController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\OqlController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/OqlController.php',
'Combodo\\iTop\\Controller\\Links\\LinkSetController' => __DIR__ . '/../..' . '/sources/Controller/Links/LinkSetController.php',
'Combodo\\iTop\\Controller\\Newsroom\\iTopNewsroomController' => __DIR__ . '/../..' . '/sources/Controller/Newsroom/iTopNewsroomController.php',
'Combodo\\iTop\\Controller\\Notifications\\ActionController' => __DIR__ . '/../..' . '/sources/Controller/Notifications/ActionController.php',
@@ -854,8 +891,119 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Form\\Validator\\MultipleChoicesValidator' => __DIR__ . '/../..' . '/sources/Form/Validator/MultipleChoicesValidator.php',
'Combodo\\iTop\\Form\\Validator\\NotEmptyExtKeyValidator' => __DIR__ . '/../..' . '/sources/Form/Validator/NotEmptyExtKeyValidator.php',
'Combodo\\iTop\\Form\\Validator\\SelectObjectValidator' => __DIR__ . '/../..' . '/sources/Form/Validator/SelectObjectValidator.php',
'Combodo\\iTop\\Forms\\Block\\AbstractFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/AbstractFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\AbstractTypeFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/AbstractTypeFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\CheckboxFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/CheckboxFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/ChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFromInputsBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/ChoiceFromInputsBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceImageFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/ChoiceImageFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\CollectionBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/CollectionBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\DateFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/DateFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\DateTimeFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/DateTimeFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\FormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/FormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\HiddenFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/HiddenFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\IntegerFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/IntegerFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\NumberFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/NumberFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\PolymorphicFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/PolymorphicFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextAreaFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/TextAreaFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Base\\TextFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/TextFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeTypeChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeTypeChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeValueChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeValueChoiceFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\Dashlet\\AggregateFunctionFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/Dashlet/AggregateFunctionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\Dashlet\\ClassAttributeGroupByFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/Dashlet/ClassAttributeGroupByFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\LabelFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/LabelFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\DataModel\\OqlFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/OqlFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\AbstractExpressionFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Expression/AbstractExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\BooleanExpressionFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Expression/BooleanExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\NumberExpressionFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Expression/NumberExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\Expression\\StringExpressionFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Expression/StringExpressionFormBlock.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockException' => __DIR__ . '/../..' . '/sources/Forms/Block/FormBlockException.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockHelper' => __DIR__ . '/../..' . '/sources/Forms/Block/FormBlockHelper.php',
'Combodo\\iTop\\Forms\\Block\\FormBlockService' => __DIR__ . '/../..' . '/sources/Forms/Block/FormBlockService.php',
'Combodo\\iTop\\Forms\\Block\\IFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/IFormBlock.php',
'Combodo\\iTop\\Forms\\Controller\\FormsController' => __DIR__ . '/../..' . '/sources/Forms/Controller/FormsController.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyHandler' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/DependencyHandler.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyMap' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/DependencyMap.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormBuilder' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/FormBuilder.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormBuilderException' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/FormBuilderException.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormHelper' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/FormHelper.php',
'Combodo\\iTop\\Forms\\FormBuilder\\FormTypeExtension' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/FormTypeExtension.php',
'Combodo\\iTop\\Forms\\FormBuilder\\ResolvedFormType' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/ResolvedFormType.php',
'Combodo\\iTop\\Forms\\FormBuilder\\ResolvedFormTypeFactory' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/ResolvedFormTypeFactory.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\ChoiceFormType' => __DIR__ . '/../..' . '/sources/Forms/FormType/Base/ChoiceFormType.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\CollectionFormType' => __DIR__ . '/../..' . '/sources/Forms/FormType/Base/CollectionFormType.php',
'Combodo\\iTop\\Forms\\FormType\\Base\\FormType' => __DIR__ . '/../..' . '/sources/Forms/FormType/Base/FormType.php',
'Combodo\\iTop\\Forms\\FormType\\DataModel\\OqlFormType' => __DIR__ . '/../..' . '/sources/Forms/FormType/DataModel/OqlFormType.php',
'Combodo\\iTop\\Forms\\FormType\\FormTypeHelper' => __DIR__ . '/../..' . '/sources/Forms/FormType/FormTypeHelper.php',
'Combodo\\iTop\\Forms\\Forms' => __DIR__ . '/../..' . '/sources/Forms/Forms.php',
'Combodo\\iTop\\Forms\\FormsException' => __DIR__ . '/../..' . '/sources/Forms/FormsException.php',
'Combodo\\iTop\\Forms\\IO\\AbstractFormIO' => __DIR__ . '/../..' . '/sources/Forms/IO/AbstractFormIO.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\AbstractConverter' => __DIR__ . '/../..' . '/sources/Forms/IO/Converter/AbstractConverter.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\ChoiceValueToLabelConverter' => __DIR__ . '/../..' . '/sources/Forms/IO/Converter/ChoiceValueToLabelConverter.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\CollectionToCountConverter' => __DIR__ . '/../..' . '/sources/Forms/IO/Converter/CollectionToCountConverter.php',
'Combodo\\iTop\\Forms\\IO\\Converter\\OqlToClassConverter' => __DIR__ . '/../..' . '/sources/Forms/IO/Converter/OqlToClassConverter.php',
'Combodo\\iTop\\Forms\\IO\\FormBinding' => __DIR__ . '/../..' . '/sources/Forms/IO/FormBinding.php',
'Combodo\\iTop\\Forms\\IO\\FormBlockIOException' => __DIR__ . '/../..' . '/sources/Forms/IO/FormBlockIOException.php',
'Combodo\\iTop\\Forms\\IO\\FormInput' => __DIR__ . '/../..' . '/sources/Forms/IO/FormInput.php',
'Combodo\\iTop\\Forms\\IO\\FormOutput' => __DIR__ . '/../..' . '/sources/Forms/IO/FormOutput.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AbstractIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/AbstractIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/AttributeIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeTypeArrayIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/AttributeTypeArrayIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\AttributeTypeIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/AttributeTypeIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\BooleanIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/BooleanIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\ClassIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/ClassIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\IntegerIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/IntegerIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\NumberIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/NumberIOFormat.php',
'Combodo\\iTop\\Forms\\IO\\Format\\StringIOFormat' => __DIR__ . '/../..' . '/sources/Forms/IO/Format/StringIOFormat.php',
'Combodo\\iTop\\Forms\\Register\\IORegister' => __DIR__ . '/../..' . '/sources/Forms/Register/IORegister.php',
'Combodo\\iTop\\Forms\\Register\\Option' => __DIR__ . '/../..' . '/sources/Forms/Register/Option.php',
'Combodo\\iTop\\Forms\\Register\\OptionsRegister' => __DIR__ . '/../..' . '/sources/Forms/Register/OptionsRegister.php',
'Combodo\\iTop\\Forms\\Register\\RegisterException' => __DIR__ . '/../..' . '/sources/Forms/Register/RegisterException.php',
'Combodo\\iTop\\Forms\\Twig\\Extension\\FormCompatibilityExtension' => __DIR__ . '/../..' . '/sources/Forms/Twig/Extension/FormCompatibilityExtension.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExist' => __DIR__ . '/../..' . '/sources/Forms/Validator/AttributeExist.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExistValidator' => __DIR__ . '/../..' . '/sources/Forms/Validator/AttributeExistValidator.php',
'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php',
'Combodo\\iTop\\PropertyType\\Compiler\\PropertyTypeCompiler' => __DIR__ . '/../..' . '/sources/PropertyType/Compiler/PropertyTypeCompiler.php',
'Combodo\\iTop\\PropertyType\\Compiler\\PropertyTypeCompilerException' => __DIR__ . '/../..' . '/sources/PropertyType/Compiler/PropertyTypeCompilerException.php',
'Combodo\\iTop\\PropertyType\\PropertyType' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyType.php',
'Combodo\\iTop\\PropertyType\\PropertyTypeDesign' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyTypeDesign.php',
'Combodo\\iTop\\PropertyType\\PropertyTypeException' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyTypeException.php',
'Combodo\\iTop\\PropertyType\\PropertyTypeFactory' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyTypeFactory.php',
'Combodo\\iTop\\PropertyType\\PropertyTypeService' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyTypeService.php',
'Combodo\\iTop\\PropertyType\\Serializer\\SerializerException' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/SerializerException.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLEncoder' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLEncoder.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\AbstractXMLFormat' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/AbstractXMLFormat.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatCSV' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatCSV.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatCollectionWithId' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatCollectionWithId.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatFactory' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatFactory.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatFlatArray' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatFlatArray.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatValueAsId' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatValueAsId.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLNormalizer' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLNormalizer.php',
'Combodo\\iTop\\PropertyType\\Serializer\\XMLSerializer' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLSerializer.php',
'Combodo\\iTop\\PropertyType\\ValueType\\AbstractValueType' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/AbstractValueType.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\AbstractBranchValueType' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/AbstractBranchValueType.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypeCollection' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/ValueTypeCollection.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypePolymorphic' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/ValueTypePolymorphic.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypePropertyTree' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/ValueTypePropertyTree.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\AbstractLeafValueType' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/AbstractLeafValueType.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeAggregateFunction' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeAggregateFunction.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeBoolean' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeBoolean.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeChoice' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeChoice.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeChoiceFromInput' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeChoiceFromInput.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClass' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeClass.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttribute' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttribute.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttributeGroupBy' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttributeGroupBy.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttributeValue' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttributeValue.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeCollectionOfValues' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeCollectionOfValues.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeIcon' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeIcon.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeInteger' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeInteger.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeLabel' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeLabel.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeOQL' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeOQL.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeProfileName' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeProfileName.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeString' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeString.php',
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeText' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeText.php',
'Combodo\\iTop\\PropertyType\\ValueType\\ValueTypeFactory' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/ValueTypeFactory.php',
'Combodo\\iTop\\Renderer\\BlockRenderer' => __DIR__ . '/../..' . '/sources/Renderer/BlockRenderer.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFormRenderer.php',
@@ -878,6 +1026,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Service\\Base\\ObjectRepository' => __DIR__ . '/../..' . '/sources/Service/Base/ObjectRepository.php',
'Combodo\\iTop\\Service\\Base\\iDataPostProcessor' => __DIR__ . '/../..' . '/sources/Service/Base/iDataPostProcessor.php',
'Combodo\\iTop\\Service\\Cache\\DataModelDependantCache' => __DIR__ . '/../..' . '/sources/Service/Cache/DataModelDependantCache.php',
'Combodo\\iTop\\Service\\DependencyInjection\\DIException' => __DIR__ . '/../..' . '/sources/Service/DependencyInjection/DIException.php',
'Combodo\\iTop\\Service\\DependencyInjection\\ServiceLocator' => __DIR__ . '/../..' . '/sources/Service/DependencyInjection/ServiceLocator.php',
'Combodo\\iTop\\Service\\Events\\Description\\EventDataDescription' => __DIR__ . '/../..' . '/sources/Service/Events/Description/EventDataDescription.php',
'Combodo\\iTop\\Service\\Events\\Description\\EventDescription' => __DIR__ . '/../..' . '/sources/Service/Events/Description/EventDescription.php',
'Combodo\\iTop\\Service\\Events\\EventData' => __DIR__ . '/../..' . '/sources/Service/Events/EventData.php',
@@ -945,19 +1095,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'DashboardLayoutThreeCols' => __DIR__ . '/../..' . '/application/dashboardlayout.class.inc.php',
'DashboardLayoutTwoCols' => __DIR__ . '/../..' . '/application/dashboardlayout.class.inc.php',
'DashboardMenuNode' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
'Dashlet' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletBadge' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletEmptyCell' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletGroupBy' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletGroupByBars' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletGroupByPie' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletGroupByTable' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletHeaderDynamic' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletHeaderStatic' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletObjectList' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletPlainText' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletProxy' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'DashletUnknown' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
'Datamatrix' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php',
'DateError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
'DateException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
@@ -3452,6 +3589,227 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Symfony\\Component\\String\\Slugger\\AsciiSlugger' => __DIR__ . '/..' . '/symfony/string/Slugger/AsciiSlugger.php',
'Symfony\\Component\\String\\Slugger\\SluggerInterface' => __DIR__ . '/..' . '/symfony/string/Slugger/SluggerInterface.php',
'Symfony\\Component\\String\\UnicodeString' => __DIR__ . '/..' . '/symfony/string/UnicodeString.php',
'Symfony\\Component\\Validator\\Attribute\\HasNamedArguments' => __DIR__ . '/..' . '/symfony/validator/Attribute/HasNamedArguments.php',
'Symfony\\Component\\Validator\\Command\\DebugCommand' => __DIR__ . '/..' . '/symfony/validator/Command/DebugCommand.php',
'Symfony\\Component\\Validator\\Constraint' => __DIR__ . '/..' . '/symfony/validator/Constraint.php',
'Symfony\\Component\\Validator\\ConstraintValidator' => __DIR__ . '/..' . '/symfony/validator/ConstraintValidator.php',
'Symfony\\Component\\Validator\\ConstraintValidatorFactory' => __DIR__ . '/..' . '/symfony/validator/ConstraintValidatorFactory.php',
'Symfony\\Component\\Validator\\ConstraintValidatorFactoryInterface' => __DIR__ . '/..' . '/symfony/validator/ConstraintValidatorFactoryInterface.php',
'Symfony\\Component\\Validator\\ConstraintValidatorInterface' => __DIR__ . '/..' . '/symfony/validator/ConstraintValidatorInterface.php',
'Symfony\\Component\\Validator\\ConstraintViolation' => __DIR__ . '/..' . '/symfony/validator/ConstraintViolation.php',
'Symfony\\Component\\Validator\\ConstraintViolationInterface' => __DIR__ . '/..' . '/symfony/validator/ConstraintViolationInterface.php',
'Symfony\\Component\\Validator\\ConstraintViolationList' => __DIR__ . '/..' . '/symfony/validator/ConstraintViolationList.php',
'Symfony\\Component\\Validator\\ConstraintViolationListInterface' => __DIR__ . '/..' . '/symfony/validator/ConstraintViolationListInterface.php',
'Symfony\\Component\\Validator\\Constraints\\AbstractComparison' => __DIR__ . '/..' . '/symfony/validator/Constraints/AbstractComparison.php',
'Symfony\\Component\\Validator\\Constraints\\AbstractComparisonValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/AbstractComparisonValidator.php',
'Symfony\\Component\\Validator\\Constraints\\All' => __DIR__ . '/..' . '/symfony/validator/Constraints/All.php',
'Symfony\\Component\\Validator\\Constraints\\AllValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/AllValidator.php',
'Symfony\\Component\\Validator\\Constraints\\AtLeastOneOf' => __DIR__ . '/..' . '/symfony/validator/Constraints/AtLeastOneOf.php',
'Symfony\\Component\\Validator\\Constraints\\AtLeastOneOfValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/AtLeastOneOfValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Bic' => __DIR__ . '/..' . '/symfony/validator/Constraints/Bic.php',
'Symfony\\Component\\Validator\\Constraints\\BicValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/BicValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Blank' => __DIR__ . '/..' . '/symfony/validator/Constraints/Blank.php',
'Symfony\\Component\\Validator\\Constraints\\BlankValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/BlankValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Callback' => __DIR__ . '/..' . '/symfony/validator/Constraints/Callback.php',
'Symfony\\Component\\Validator\\Constraints\\CallbackValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CallbackValidator.php',
'Symfony\\Component\\Validator\\Constraints\\CardScheme' => __DIR__ . '/..' . '/symfony/validator/Constraints/CardScheme.php',
'Symfony\\Component\\Validator\\Constraints\\CardSchemeValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CardSchemeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Cascade' => __DIR__ . '/..' . '/symfony/validator/Constraints/Cascade.php',
'Symfony\\Component\\Validator\\Constraints\\Choice' => __DIR__ . '/..' . '/symfony/validator/Constraints/Choice.php',
'Symfony\\Component\\Validator\\Constraints\\ChoiceValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ChoiceValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Cidr' => __DIR__ . '/..' . '/symfony/validator/Constraints/Cidr.php',
'Symfony\\Component\\Validator\\Constraints\\CidrValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CidrValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Collection' => __DIR__ . '/..' . '/symfony/validator/Constraints/Collection.php',
'Symfony\\Component\\Validator\\Constraints\\CollectionValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CollectionValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Composite' => __DIR__ . '/..' . '/symfony/validator/Constraints/Composite.php',
'Symfony\\Component\\Validator\\Constraints\\Compound' => __DIR__ . '/..' . '/symfony/validator/Constraints/Compound.php',
'Symfony\\Component\\Validator\\Constraints\\CompoundValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CompoundValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Count' => __DIR__ . '/..' . '/symfony/validator/Constraints/Count.php',
'Symfony\\Component\\Validator\\Constraints\\CountValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CountValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Country' => __DIR__ . '/..' . '/symfony/validator/Constraints/Country.php',
'Symfony\\Component\\Validator\\Constraints\\CountryValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CountryValidator.php',
'Symfony\\Component\\Validator\\Constraints\\CssColor' => __DIR__ . '/..' . '/symfony/validator/Constraints/CssColor.php',
'Symfony\\Component\\Validator\\Constraints\\CssColorValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CssColorValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Currency' => __DIR__ . '/..' . '/symfony/validator/Constraints/Currency.php',
'Symfony\\Component\\Validator\\Constraints\\CurrencyValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/CurrencyValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Date' => __DIR__ . '/..' . '/symfony/validator/Constraints/Date.php',
'Symfony\\Component\\Validator\\Constraints\\DateTime' => __DIR__ . '/..' . '/symfony/validator/Constraints/DateTime.php',
'Symfony\\Component\\Validator\\Constraints\\DateTimeValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/DateTimeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\DateValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/DateValidator.php',
'Symfony\\Component\\Validator\\Constraints\\DisableAutoMapping' => __DIR__ . '/..' . '/symfony/validator/Constraints/DisableAutoMapping.php',
'Symfony\\Component\\Validator\\Constraints\\DivisibleBy' => __DIR__ . '/..' . '/symfony/validator/Constraints/DivisibleBy.php',
'Symfony\\Component\\Validator\\Constraints\\DivisibleByValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/DivisibleByValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Email' => __DIR__ . '/..' . '/symfony/validator/Constraints/Email.php',
'Symfony\\Component\\Validator\\Constraints\\EmailValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/EmailValidator.php',
'Symfony\\Component\\Validator\\Constraints\\EnableAutoMapping' => __DIR__ . '/..' . '/symfony/validator/Constraints/EnableAutoMapping.php',
'Symfony\\Component\\Validator\\Constraints\\EqualTo' => __DIR__ . '/..' . '/symfony/validator/Constraints/EqualTo.php',
'Symfony\\Component\\Validator\\Constraints\\EqualToValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/EqualToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Existence' => __DIR__ . '/..' . '/symfony/validator/Constraints/Existence.php',
'Symfony\\Component\\Validator\\Constraints\\Expression' => __DIR__ . '/..' . '/symfony/validator/Constraints/Expression.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageProvider' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionLanguageProvider.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntax' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionLanguageSyntax.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntaxValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionLanguageSyntaxValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionSyntax' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionSyntax.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionSyntaxValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionSyntaxValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ExpressionValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ExpressionValidator.php',
'Symfony\\Component\\Validator\\Constraints\\File' => __DIR__ . '/..' . '/symfony/validator/Constraints/File.php',
'Symfony\\Component\\Validator\\Constraints\\FileValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/FileValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThan' => __DIR__ . '/..' . '/symfony/validator/Constraints/GreaterThan.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqual' => __DIR__ . '/..' . '/symfony/validator/Constraints/GreaterThanOrEqual.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqualValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/GreaterThanOrEqualValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GreaterThanValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/GreaterThanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\GroupSequence' => __DIR__ . '/..' . '/symfony/validator/Constraints/GroupSequence.php',
'Symfony\\Component\\Validator\\Constraints\\GroupSequenceProvider' => __DIR__ . '/..' . '/symfony/validator/Constraints/GroupSequenceProvider.php',
'Symfony\\Component\\Validator\\Constraints\\Hostname' => __DIR__ . '/..' . '/symfony/validator/Constraints/Hostname.php',
'Symfony\\Component\\Validator\\Constraints\\HostnameValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/HostnameValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Iban' => __DIR__ . '/..' . '/symfony/validator/Constraints/Iban.php',
'Symfony\\Component\\Validator\\Constraints\\IbanValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IbanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IdenticalTo' => __DIR__ . '/..' . '/symfony/validator/Constraints/IdenticalTo.php',
'Symfony\\Component\\Validator\\Constraints\\IdenticalToValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IdenticalToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Image' => __DIR__ . '/..' . '/symfony/validator/Constraints/Image.php',
'Symfony\\Component\\Validator\\Constraints\\ImageValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ImageValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Ip' => __DIR__ . '/..' . '/symfony/validator/Constraints/Ip.php',
'Symfony\\Component\\Validator\\Constraints\\IpValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IpValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsFalse' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsFalse.php',
'Symfony\\Component\\Validator\\Constraints\\IsFalseValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsFalseValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsNull' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsNull.php',
'Symfony\\Component\\Validator\\Constraints\\IsNullValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsNullValidator.php',
'Symfony\\Component\\Validator\\Constraints\\IsTrue' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsTrue.php',
'Symfony\\Component\\Validator\\Constraints\\IsTrueValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsTrueValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Isbn' => __DIR__ . '/..' . '/symfony/validator/Constraints/Isbn.php',
'Symfony\\Component\\Validator\\Constraints\\IsbnValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsbnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Isin' => __DIR__ . '/..' . '/symfony/validator/Constraints/Isin.php',
'Symfony\\Component\\Validator\\Constraints\\IsinValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IsinValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Issn' => __DIR__ . '/..' . '/symfony/validator/Constraints/Issn.php',
'Symfony\\Component\\Validator\\Constraints\\IssnValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/IssnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Json' => __DIR__ . '/..' . '/symfony/validator/Constraints/Json.php',
'Symfony\\Component\\Validator\\Constraints\\JsonValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/JsonValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Language' => __DIR__ . '/..' . '/symfony/validator/Constraints/Language.php',
'Symfony\\Component\\Validator\\Constraints\\LanguageValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LanguageValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Length' => __DIR__ . '/..' . '/symfony/validator/Constraints/Length.php',
'Symfony\\Component\\Validator\\Constraints\\LengthValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LengthValidator.php',
'Symfony\\Component\\Validator\\Constraints\\LessThan' => __DIR__ . '/..' . '/symfony/validator/Constraints/LessThan.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanOrEqual' => __DIR__ . '/..' . '/symfony/validator/Constraints/LessThanOrEqual.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanOrEqualValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LessThanOrEqualValidator.php',
'Symfony\\Component\\Validator\\Constraints\\LessThanValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LessThanValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Locale' => __DIR__ . '/..' . '/symfony/validator/Constraints/Locale.php',
'Symfony\\Component\\Validator\\Constraints\\LocaleValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LocaleValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Luhn' => __DIR__ . '/..' . '/symfony/validator/Constraints/Luhn.php',
'Symfony\\Component\\Validator\\Constraints\\LuhnValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/LuhnValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Negative' => __DIR__ . '/..' . '/symfony/validator/Constraints/Negative.php',
'Symfony\\Component\\Validator\\Constraints\\NegativeOrZero' => __DIR__ . '/..' . '/symfony/validator/Constraints/NegativeOrZero.php',
'Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharacters' => __DIR__ . '/..' . '/symfony/validator/Constraints/NoSuspiciousCharacters.php',
'Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharactersValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NoSuspiciousCharactersValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotBlank' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotBlank.php',
'Symfony\\Component\\Validator\\Constraints\\NotBlankValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotBlankValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotCompromisedPassword' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotCompromisedPassword.php',
'Symfony\\Component\\Validator\\Constraints\\NotCompromisedPasswordValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotCompromisedPasswordValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotEqualTo' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotEqualTo.php',
'Symfony\\Component\\Validator\\Constraints\\NotEqualToValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotEqualToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotIdenticalTo' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotIdenticalTo.php',
'Symfony\\Component\\Validator\\Constraints\\NotIdenticalToValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotIdenticalToValidator.php',
'Symfony\\Component\\Validator\\Constraints\\NotNull' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotNull.php',
'Symfony\\Component\\Validator\\Constraints\\NotNullValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/NotNullValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Optional' => __DIR__ . '/..' . '/symfony/validator/Constraints/Optional.php',
'Symfony\\Component\\Validator\\Constraints\\PasswordStrength' => __DIR__ . '/..' . '/symfony/validator/Constraints/PasswordStrength.php',
'Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/PasswordStrengthValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Positive' => __DIR__ . '/..' . '/symfony/validator/Constraints/Positive.php',
'Symfony\\Component\\Validator\\Constraints\\PositiveOrZero' => __DIR__ . '/..' . '/symfony/validator/Constraints/PositiveOrZero.php',
'Symfony\\Component\\Validator\\Constraints\\Range' => __DIR__ . '/..' . '/symfony/validator/Constraints/Range.php',
'Symfony\\Component\\Validator\\Constraints\\RangeValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/RangeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Regex' => __DIR__ . '/..' . '/symfony/validator/Constraints/Regex.php',
'Symfony\\Component\\Validator\\Constraints\\RegexValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/RegexValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Required' => __DIR__ . '/..' . '/symfony/validator/Constraints/Required.php',
'Symfony\\Component\\Validator\\Constraints\\Sequentially' => __DIR__ . '/..' . '/symfony/validator/Constraints/Sequentially.php',
'Symfony\\Component\\Validator\\Constraints\\SequentiallyValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/SequentiallyValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Time' => __DIR__ . '/..' . '/symfony/validator/Constraints/Time.php',
'Symfony\\Component\\Validator\\Constraints\\TimeValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/TimeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Timezone' => __DIR__ . '/..' . '/symfony/validator/Constraints/Timezone.php',
'Symfony\\Component\\Validator\\Constraints\\TimezoneValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/TimezoneValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Traverse' => __DIR__ . '/..' . '/symfony/validator/Constraints/Traverse.php',
'Symfony\\Component\\Validator\\Constraints\\Type' => __DIR__ . '/..' . '/symfony/validator/Constraints/Type.php',
'Symfony\\Component\\Validator\\Constraints\\TypeValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/TypeValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Ulid' => __DIR__ . '/..' . '/symfony/validator/Constraints/Ulid.php',
'Symfony\\Component\\Validator\\Constraints\\UlidValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/UlidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Unique' => __DIR__ . '/..' . '/symfony/validator/Constraints/Unique.php',
'Symfony\\Component\\Validator\\Constraints\\UniqueValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/UniqueValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Url' => __DIR__ . '/..' . '/symfony/validator/Constraints/Url.php',
'Symfony\\Component\\Validator\\Constraints\\UrlValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/UrlValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Uuid' => __DIR__ . '/..' . '/symfony/validator/Constraints/Uuid.php',
'Symfony\\Component\\Validator\\Constraints\\UuidValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/UuidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\Valid' => __DIR__ . '/..' . '/symfony/validator/Constraints/Valid.php',
'Symfony\\Component\\Validator\\Constraints\\ValidValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/ValidValidator.php',
'Symfony\\Component\\Validator\\Constraints\\When' => __DIR__ . '/..' . '/symfony/validator/Constraints/When.php',
'Symfony\\Component\\Validator\\Constraints\\WhenValidator' => __DIR__ . '/..' . '/symfony/validator/Constraints/WhenValidator.php',
'Symfony\\Component\\Validator\\Constraints\\ZeroComparisonConstraintTrait' => __DIR__ . '/..' . '/symfony/validator/Constraints/ZeroComparisonConstraintTrait.php',
'Symfony\\Component\\Validator\\ContainerConstraintValidatorFactory' => __DIR__ . '/..' . '/symfony/validator/ContainerConstraintValidatorFactory.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContext' => __DIR__ . '/..' . '/symfony/validator/Context/ExecutionContext.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextFactory' => __DIR__ . '/..' . '/symfony/validator/Context/ExecutionContextFactory.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextFactoryInterface' => __DIR__ . '/..' . '/symfony/validator/Context/ExecutionContextFactoryInterface.php',
'Symfony\\Component\\Validator\\Context\\ExecutionContextInterface' => __DIR__ . '/..' . '/symfony/validator/Context/ExecutionContextInterface.php',
'Symfony\\Component\\Validator\\DataCollector\\ValidatorDataCollector' => __DIR__ . '/..' . '/symfony/validator/DataCollector/ValidatorDataCollector.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddAutoMappingConfigurationPass' => __DIR__ . '/..' . '/symfony/validator/DependencyInjection/AddAutoMappingConfigurationPass.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddConstraintValidatorsPass' => __DIR__ . '/..' . '/symfony/validator/DependencyInjection/AddConstraintValidatorsPass.php',
'Symfony\\Component\\Validator\\DependencyInjection\\AddValidatorInitializersPass' => __DIR__ . '/..' . '/symfony/validator/DependencyInjection/AddValidatorInitializersPass.php',
'Symfony\\Component\\Validator\\Exception\\BadMethodCallException' => __DIR__ . '/..' . '/symfony/validator/Exception/BadMethodCallException.php',
'Symfony\\Component\\Validator\\Exception\\ConstraintDefinitionException' => __DIR__ . '/..' . '/symfony/validator/Exception/ConstraintDefinitionException.php',
'Symfony\\Component\\Validator\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/validator/Exception/ExceptionInterface.php',
'Symfony\\Component\\Validator\\Exception\\GroupDefinitionException' => __DIR__ . '/..' . '/symfony/validator/Exception/GroupDefinitionException.php',
'Symfony\\Component\\Validator\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/validator/Exception/InvalidArgumentException.php',
'Symfony\\Component\\Validator\\Exception\\InvalidOptionsException' => __DIR__ . '/..' . '/symfony/validator/Exception/InvalidOptionsException.php',
'Symfony\\Component\\Validator\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/validator/Exception/LogicException.php',
'Symfony\\Component\\Validator\\Exception\\MappingException' => __DIR__ . '/..' . '/symfony/validator/Exception/MappingException.php',
'Symfony\\Component\\Validator\\Exception\\MissingOptionsException' => __DIR__ . '/..' . '/symfony/validator/Exception/MissingOptionsException.php',
'Symfony\\Component\\Validator\\Exception\\NoSuchMetadataException' => __DIR__ . '/..' . '/symfony/validator/Exception/NoSuchMetadataException.php',
'Symfony\\Component\\Validator\\Exception\\OutOfBoundsException' => __DIR__ . '/..' . '/symfony/validator/Exception/OutOfBoundsException.php',
'Symfony\\Component\\Validator\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/validator/Exception/RuntimeException.php',
'Symfony\\Component\\Validator\\Exception\\UnexpectedTypeException' => __DIR__ . '/..' . '/symfony/validator/Exception/UnexpectedTypeException.php',
'Symfony\\Component\\Validator\\Exception\\UnexpectedValueException' => __DIR__ . '/..' . '/symfony/validator/Exception/UnexpectedValueException.php',
'Symfony\\Component\\Validator\\Exception\\UnsupportedMetadataException' => __DIR__ . '/..' . '/symfony/validator/Exception/UnsupportedMetadataException.php',
'Symfony\\Component\\Validator\\Exception\\ValidationFailedException' => __DIR__ . '/..' . '/symfony/validator/Exception/ValidationFailedException.php',
'Symfony\\Component\\Validator\\Exception\\ValidatorException' => __DIR__ . '/..' . '/symfony/validator/Exception/ValidatorException.php',
'Symfony\\Component\\Validator\\GroupProviderInterface' => __DIR__ . '/..' . '/symfony/validator/GroupProviderInterface.php',
'Symfony\\Component\\Validator\\GroupSequenceProviderInterface' => __DIR__ . '/..' . '/symfony/validator/GroupSequenceProviderInterface.php',
'Symfony\\Component\\Validator\\Mapping\\AutoMappingStrategy' => __DIR__ . '/..' . '/symfony/validator/Mapping/AutoMappingStrategy.php',
'Symfony\\Component\\Validator\\Mapping\\CascadingStrategy' => __DIR__ . '/..' . '/symfony/validator/Mapping/CascadingStrategy.php',
'Symfony\\Component\\Validator\\Mapping\\ClassMetadata' => __DIR__ . '/..' . '/symfony/validator/Mapping/ClassMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\ClassMetadataInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/ClassMetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\BlackHoleMetadataFactory' => __DIR__ . '/..' . '/symfony/validator/Mapping/Factory/BlackHoleMetadataFactory.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\LazyLoadingMetadataFactory' => __DIR__ . '/..' . '/symfony/validator/Mapping/Factory/LazyLoadingMetadataFactory.php',
'Symfony\\Component\\Validator\\Mapping\\Factory\\MetadataFactoryInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/Factory/MetadataFactoryInterface.php',
'Symfony\\Component\\Validator\\Mapping\\GenericMetadata' => __DIR__ . '/..' . '/symfony/validator/Mapping/GenericMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\GetterMetadata' => __DIR__ . '/..' . '/symfony/validator/Mapping/GetterMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AbstractLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/AbstractLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AnnotationLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/AnnotationLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AttributeLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/AttributeLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\AutoMappingTrait' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/AutoMappingTrait.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\FileLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/FileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\FilesLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/FilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\LoaderChain' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/LoaderChain.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\LoaderInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/LoaderInterface.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\PropertyInfoLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/PropertyInfoLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\StaticMethodLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/StaticMethodLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\XmlFileLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/XmlFileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\XmlFilesLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/XmlFilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\YamlFileLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/YamlFileLoader.php',
'Symfony\\Component\\Validator\\Mapping\\Loader\\YamlFilesLoader' => __DIR__ . '/..' . '/symfony/validator/Mapping/Loader/YamlFilesLoader.php',
'Symfony\\Component\\Validator\\Mapping\\MemberMetadata' => __DIR__ . '/..' . '/symfony/validator/Mapping/MemberMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\MetadataInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/MetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\PropertyMetadata' => __DIR__ . '/..' . '/symfony/validator/Mapping/PropertyMetadata.php',
'Symfony\\Component\\Validator\\Mapping\\PropertyMetadataInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/PropertyMetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\TraversalStrategy' => __DIR__ . '/..' . '/symfony/validator/Mapping/TraversalStrategy.php',
'Symfony\\Component\\Validator\\ObjectInitializerInterface' => __DIR__ . '/..' . '/symfony/validator/ObjectInitializerInterface.php',
'Symfony\\Component\\Validator\\Util\\PropertyPath' => __DIR__ . '/..' . '/symfony/validator/Util/PropertyPath.php',
'Symfony\\Component\\Validator\\Validation' => __DIR__ . '/..' . '/symfony/validator/Validation.php',
'Symfony\\Component\\Validator\\ValidatorBuilder' => __DIR__ . '/..' . '/symfony/validator/ValidatorBuilder.php',
'Symfony\\Component\\Validator\\Validator\\ContextualValidatorInterface' => __DIR__ . '/..' . '/symfony/validator/Validator/ContextualValidatorInterface.php',
'Symfony\\Component\\Validator\\Validator\\LazyProperty' => __DIR__ . '/..' . '/symfony/validator/Validator/LazyProperty.php',
'Symfony\\Component\\Validator\\Validator\\RecursiveContextualValidator' => __DIR__ . '/..' . '/symfony/validator/Validator/RecursiveContextualValidator.php',
'Symfony\\Component\\Validator\\Validator\\RecursiveValidator' => __DIR__ . '/..' . '/symfony/validator/Validator/RecursiveValidator.php',
'Symfony\\Component\\Validator\\Validator\\TraceableValidator' => __DIR__ . '/..' . '/symfony/validator/Validator/TraceableValidator.php',
'Symfony\\Component\\Validator\\Validator\\ValidatorInterface' => __DIR__ . '/..' . '/symfony/validator/Validator/ValidatorInterface.php',
'Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilder' => __DIR__ . '/..' . '/symfony/validator/Violation/ConstraintViolationBuilder.php',
'Symfony\\Component\\Validator\\Violation\\ConstraintViolationBuilderInterface' => __DIR__ . '/..' . '/symfony/validator/Violation/ConstraintViolationBuilderInterface.php',
'Symfony\\Component\\VarDumper\\Caster\\AmqpCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/AmqpCaster.php',
'Symfony\\Component\\VarDumper\\Caster\\ArgsStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ArgsStub.php',
'Symfony\\Component\\VarDumper\\Caster\\Caster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/Caster.php',

Some files were not shown because too many files have changed in this diff Show More