N°9065 - XML Definition for Dashlet properties

This commit is contained in:
Eric Espie
2026-01-06 15:59:46 +01:00
parent 904cd0b518
commit efb1bd765b
56 changed files with 2433 additions and 1270 deletions

View File

@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?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> <classes>
<class id="AbstractResource" _delta="define"> <class id="AbstractResource" _delta="define">
<parent>cmdbAbstractObject</parent> <parent>cmdbAbstractObject</parent>
<properties> <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 herited by abstract resource access control classes. Generally controlled using UR_ACTION_MODIFY access right. */</comment>
<abstract>true</abstract> <abstract>true</abstract>
</properties> </properties>
<presentation/> <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> <description><![CDATA[Inform the listeners about the connection states]]></description>
<event_data> <event_data>
<event_datum id="code"> <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> <type>integer</type>
</event_datum> </event_datum>
<event_datum id="state"> <event_datum id="state">
@@ -849,34 +851,31 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
</methods> </methods>
</class> </class>
</classes> </classes>
<property_trees _delta="define" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://www.combodo.com/itop-schema/3.3"> <property_types _delta="define">
<property_tree id="DashletGroupBy" xsi:type="Combodo-PropertyTree"> <property_type id="Dashlet" xsi:type="Combodo-AbstractPropertyType"/>
<property_type id="DashletGroupBy" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends> <extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<label>UI:DashletGroupBy:Title</label>
<nodes> <nodes>
<node id="title"> <node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletGroupBy:Prop-Title</label> <label>UI:DashletGroupBy:Prop-Title</label>
<value-type xsi:type="Combodo-ValueType-Label"/><!-- LabelFormBlock -->
</node> </node>
<node id="query"> <node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletGroupBy:Prop-Query</label> <label>UI:DashletGroupBy:Prop-Query</label>
<value-type xsi:type="Combodo-ValueType-OQL">
<data-transform> <data-transform>
<xml-node-empty-not-allowed/> <!-- mandatory quoi ! --> <xml-node-empty-not-allowed/> <!-- mandatory quoi ! -->
</data-transform> </data-transform>
</value-type>
</node> </node>
<node id="group_by"> <node id="group_by" xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
<label>UI:DashletGroupBy:Prop-GroupBy</label> <label>UI:DashletGroupBy:Prop-GroupBy</label>
<value-type xsi:type="Combodo-ValueType-ClassAttributeGroupBy"> <!-- par défaut, il proposera le state attribute de la classe -->
<class>{{query.selected_class}}</class>
<data-transform> <data-transform>
<xml-node-empty-not-allowed/> <xml-node-empty-not-allowed/>
</data-transform> </data-transform>
</value-type> <class>{{query.selected_class}}</class>
</node> </node>
<node id="style"> <!-- possible de le cacher, etc.... celui-ci nous met dedans --> <node id="style" xsi:type="Combodo-ValueType-Choice"> <!-- Possible de le cacher, etc celui-ci nous met dedans -->
<label>UI:DashletGroupBy:Prop-Style</label> <label>UI:DashletGroupBy:Prop-Style</label>
<value-type xsi:type="Combodo-ValueType-Choice">
<data-transform> <data-transform>
<xml-node-empty-defaults-to>bars</xml-node-empty-defaults-to> <xml-node-empty-defaults-to>bars</xml-node-empty-defaults-to>
</data-transform> </data-transform>
@@ -891,31 +890,25 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
<label>UI:DashletGroupByTable:Label</label> <label>UI:DashletGroupByTable:Label</label>
</value> </value>
</values> </values>
</value-type>
</node> </node>
<node id="aggregation_function"> <node id="aggregation_function" xsi:type="Combodo-ValueType-AggregateFunction">
<label>UI:DashletGroupBy:Prop-Function</label> <label>UI:DashletGroupBy:Prop-Function</label>
<value-type xsi:type="Combodo-ValueType-AggregateFunction"> <!-- par défaut : count -->
<data-transform> <data-transform>
<xml-node-empty-not-allowed/> <!-- mandatory quoi ! --> <xml-node-empty-not-allowed/> <!-- mandatory quoi ! -->
</data-transform> </data-transform>
<class>{{query.selected_class}}</class> <!-- pour savoir si il y a des attributs additionnables --> <class>{{query.selected_class}}</class> <!-- pour savoir si il y a des attributs additionnables -->
</value-type>
</node> </node>
<node id="aggregation_attribute"> <node id="aggregation_attribute" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:DashletGroupBy:Prop-FunctionAttribute</label> <label>UI:DashletGroupBy:Prop-FunctionAttribute</label>
<relevance-condition>{{aggregation_function.value != 'count'}}</relevance-condition> <relevance-condition>{{aggregation_function.value != 'count'}}</relevance-condition>
<value-type xsi:type="Combodo-ValueType-ClassAttribute">
<data-transform> <data-transform>
<xml-node-empty-not-allowed/> <!-- mandatory quoi ! --> <xml-node-empty-not-allowed/> <!-- mandatory quoi ! -->
</data-transform> </data-transform>
<class>{{query.selected_class}}</class> <class>{{query.selected_class}}</class>
<category>numeric</category> <category>numeric</category>
</value-type>
</node> </node>
<node id="order_by"> <node id="order_by" xsi:type="Combodo-ValueType-ChoiceFromInput">
<label>UI:DashletGroupBy:Prop-OrderField</label> <label>UI:DashletGroupBy:Prop-OrderField</label>
<value-type xsi:type="Combodo-ValueType-ChoiceFromInput">
<values> <values>
<value id="attribute"> <value id="attribute">
<label>{{aggregation_attribute.label}}</label> <label>{{aggregation_attribute.label}}</label>
@@ -924,16 +917,13 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
<label>{{aggregation_function.label}}</label> <label>{{aggregation_function.label}}</label>
</value> </value>
</values> </values>
</value-type>
</node> </node>
<node id="limit"> <node id="limit" xsi:type="Combodo-ValueType-Integer">
<label>UI:DashletGroupBy:Prop-Limit</label> <label>UI:DashletGroupBy:Prop-Limit</label>
<relevance-condition>{{order_by.value = 'function'}}</relevance-condition> <relevance-condition>{{order_by.value = 'function'}}</relevance-condition>
<value-type xsi:type="Combodo-ValueType-Integer"/>
</node> </node>
<node id="order_direction"> <node id="order_direction" xsi:type="Combodo-ValueType-Choice">
<label>UI:DashletGroupBy:Prop-OrderDirection</label> <label>UI:DashletGroupBy:Prop-OrderDirection</label>
<value-type xsi:type="Combodo-ValueType-Choice">
<data-transform> <data-transform>
<xml-node-empty-not-allowed/> <xml-node-empty-not-allowed/>
</data-transform> </data-transform>
@@ -945,98 +935,87 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
<label>UI:DashletGroupBy:Order:desc</label> <label>UI:DashletGroupBy:Order:desc</label>
</value> </value>
</values> </values>
</value-type>
<display-default>desc</display-default>
</node> </node>
</nodes> </nodes>
</property_tree> </definition>
<property_tree id="DashletBadge" xsi:type="Combodo-PropertyTree"> </property_type>
<property_type id="DashletBadge" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends> <extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="class"> <node id="class" xsi:type="Combodo-ValueType-Class">
<label>UI:DashletBadge:Prop-Class</label> <label>UI:DashletBadge:Prop-Class</label>
<value-type xsi:type="Combodo-ValueType-Class">
<categories-csv>bizmodel</categories-csv> <categories-csv>bizmodel</categories-csv>
</value-type>
</node> </node>
</nodes> </nodes>
</property_tree> </definition>
<property_tree id="DashletHeaderDynamic" xsi:type="Combodo-PropertyTree"> </property_type>
<property_type id="DashletHeaderDynamic" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends> <extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<label>UI:DashletHeaderDynamic:Title</label>
<nodes> <nodes>
<node id="title"> <node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletHeaderDynamic:Prop-Title</label> <label>UI:DashletHeaderDynamic:Prop-Title</label>
<value-type xsi:type="Combodo-ValueType-Label">
<not-blank/>
</value-type>
</node> </node>
<node id="icon"> <node id="icon" xsi:type="Combodo-ValueType-Icon">
<label>UI:DashletHeaderDynamic:Prop-Icon</label> <label>UI:DashletHeaderDynamic:Prop-Icon</label>
<value-type xsi:type="Combodo-ValueType-Icon">
</value-type>
</node> </node>
<node id="subtitle"> <node id="subtitle" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletHeaderDynamic:Prop-Subtitle</label> <label>UI:DashletHeaderDynamic:Prop-Subtitle</label>
<value-type xsi:type="Combodo-ValueType-Label"/>
</node> </node>
<node id="query"> <node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletHeaderDynamic:Prop-Query</label> <label>UI:DashletHeaderDynamic:Prop-Query</label>
<value-type xsi:type="Combodo-ValueType-OQL">
<data-transform> <data-transform>
<xml-node-empty-not-allowed/> <xml-node-empty-not-allowed/>
</data-transform> </data-transform>
</value-type>
</node> </node>
<node id="group_by"> <node id="group_by" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:DashletHeaderDynamic:Prop-GroupBy</label> <label>UI:DashletHeaderDynamic:Prop-GroupBy</label>
<value-type xsi:type="Combodo-ValueType-ClassAttribute">
<data-transform> <data-transform>
<xml-node-empty-not-allowed/> <xml-node-empty-not-allowed/>
</data-transform> </data-transform>
<class>{{query.selected_class}}</class> <class>{{query.selected_class}}</class>
<category>enum</category> <category>enum</category>
</value-type>
</node> </node>
<node id="values"> <node id="values" xsi:type="Combodo-ValueType-CollectionOfValues">
<label>UI:DashletHeaderDynamic:Prop-Values</label> <label>UI:DashletHeaderDynamic:Prop-Values</label>
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
<data-transform> <data-transform>
<xml-format xsi:type="xml-format-csv"/> <xml-format xsi:type="xml-format-csv"/>
</data-transform> </data-transform>
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
<class>{{query.selected_class}}</class> <class>{{query.selected_class}}</class>
<attribute>{{group_by.attribute}}</attribute> <attribute>{{group_by.attribute}}</attribute>
</value-type> </value-type>
</node> </node>
</nodes> </nodes>
</property_tree> </definition>
<property_tree id="DashletHeaderStatic" xsi:type="Combodo-PropertyTree"> </property_type>
<property_type id="DashletHeaderStatic" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends> <extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="title"> <node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletHeaderStatic:Prop-Title</label> <label>UI:DashletHeaderStatic:Prop-Title</label>
<value-type xsi:type="Combodo-ValueType-Label"/>
</node> </node>
<node id="icon"> <node id="icon" xsi:type="Combodo-ValueType-Icon">
<label>UI:DashletHeaderStatic:Prop-Icon</label> <label>UI:DashletHeaderStatic:Prop-Icon</label>
<value-type xsi:type="Combodo-ValueType-Icon"/>
</node> </node>
</nodes> </nodes>
</property_tree> </definition>
<property_tree id="DashletObjectList" xsi:type="Combodo-PropertyTree"> </property_type>
<property_type id="DashletObjectList" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends> <extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="title"> <node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletObjectList:Prop-Title</label> <label>UI:DashletObjectList:Prop-Title</label>
<value-type xsi:type="Combodo-ValueType-Label">
</value-type>
</node> </node>
<node id="query"> <node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletObjectList:Prop-Query</label> <label>UI:DashletObjectList:Prop-Query</label>
<value-type xsi:type="Combodo-ValueType-OQL"/>
</node> </node>
<node id="menu"> <node id="menu" xsi:type="Combodo-ValueType-Boolean">
<label>UI:DashletObjectList:Prop-Menu</label> <label>UI:DashletObjectList:Prop-Menu</label>
<value-type xsi:type="Combodo-ValueType-Boolean">
<on> <on>
<!-- not so cute, but matches exactly 3.2 implementation of boolean fields --> <!-- not so cute, but matches exactly 3.2 implementation of boolean fields -->
<label>UI:UserManagement:ActionAllowed:Yes</label> <label>UI:UserManagement:ActionAllowed:Yes</label>
@@ -1046,22 +1025,20 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
<label>UI:UserManagement:ActionAllowed:No</label> <label>UI:UserManagement:ActionAllowed:No</label>
<value>false</value> <value>false</value>
</off> </off>
</value-type>
</node> </node>
</nodes> </nodes>
</property_tree> </definition>
<property_tree id="DashletPlainText" xsi:type="Combodo-PropertyTree"> </property_type>
<property_type id="DashletPlainText" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends> <extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="text"> <node id="text" xsi:type="Combodo-ValueType-Text">
<label>UI:DashletPlainText:Prop-Text</label> <label>UI:DashletPlainText:Prop-Text</label>
<constraints>
<not_blank/>
</constraints>
<value-type xsi:type="Combodo-ValueType-Text"/>
</node> </node>
</nodes> </nodes>
</property_tree> </definition>
</property_trees> </property_type>
</property_types>
</meta> </meta>
</itop_design> </itop_design>

View File

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

View File

@@ -507,8 +507,6 @@ return array(
'Combodo\\iTop\\Forms\\Block\\FormBlockHelper' => $baseDir . '/sources/Forms/Block/FormBlockHelper.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\\FormBlockService' => $baseDir . '/sources/Forms/Block/FormBlockService.php',
'Combodo\\iTop\\Forms\\Block\\IFormBlock' => $baseDir . '/sources/Forms/Block/IFormBlock.php', 'Combodo\\iTop\\Forms\\Block\\IFormBlock' => $baseDir . '/sources/Forms/Block/IFormBlock.php',
'Combodo\\iTop\\Forms\\Compiler\\FormsCompiler' => $baseDir . '/sources/Forms/Compiler/FormsCompiler.php',
'Combodo\\iTop\\Forms\\Compiler\\FormsCompilerException' => $baseDir . '/sources/Forms/Compiler/FormsCompilerException.php',
'Combodo\\iTop\\Forms\\Controller\\FormsController' => $baseDir . '/sources/Forms/Controller/FormsController.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\\DependencyHandler' => $baseDir . '/sources/Forms/FormBuilder/DependencyHandler.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyMap' => $baseDir . '/sources/Forms/FormBuilder/DependencyMap.php', 'Combodo\\iTop\\Forms\\FormBuilder\\DependencyMap' => $baseDir . '/sources/Forms/FormBuilder/DependencyMap.php',
@@ -551,30 +549,35 @@ return array(
'Combodo\\iTop\\Forms\\Validator\\AttributeExist' => $baseDir . '/sources/Forms/Validator/AttributeExist.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\\Forms\\Validator\\AttributeExistValidator' => $baseDir . '/sources/Forms/Validator/AttributeExistValidator.php',
'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php', 'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php',
'Combodo\\iTop\\PropertyTree\\AbstractProperty' => $baseDir . '/sources/PropertyTree/AbstractProperty.php', 'Combodo\\iTop\\PropertyType\\Compiler\\PropertyTypeCompiler' => $baseDir . '/sources/PropertyType/Compiler/PropertyTypeCompiler.php',
'Combodo\\iTop\\PropertyTree\\Property' => $baseDir . '/sources/PropertyTree/Property.php', 'Combodo\\iTop\\PropertyType\\Compiler\\PropertyTypeCompilerException' => $baseDir . '/sources/PropertyType/Compiler/PropertyTypeCompilerException.php',
'Combodo\\iTop\\PropertyTree\\PropertyTree' => $baseDir . '/sources/PropertyTree/PropertyTree.php', 'Combodo\\iTop\\PropertyType\\PropertyType' => $baseDir . '/sources/PropertyType/PropertyType.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeDesign' => $baseDir . '/sources/PropertyTree/PropertyTreeDesign.php', 'Combodo\\iTop\\PropertyType\\PropertyTypeDesign' => $baseDir . '/sources/PropertyType/PropertyTypeDesign.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeException' => $baseDir . '/sources/PropertyTree/PropertyTreeException.php', 'Combodo\\iTop\\PropertyType\\PropertyTypeException' => $baseDir . '/sources/PropertyType/PropertyTypeException.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeFactory' => $baseDir . '/sources/PropertyTree/PropertyTreeFactory.php', 'Combodo\\iTop\\PropertyType\\PropertyTypeFactory' => $baseDir . '/sources/PropertyType/PropertyTypeFactory.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\AbstractValueType' => $baseDir . '/sources/PropertyTree/ValueType/AbstractValueType.php', 'Combodo\\iTop\\PropertyType\\PropertyTypeService' => $baseDir . '/sources/PropertyType/PropertyTypeService.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeAggregateFunction' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeAggregateFunction.php', 'Combodo\\iTop\\PropertyType\\ValueType\\AbstractValueType' => $baseDir . '/sources/PropertyType/ValueType/AbstractValueType.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeBoolean' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeBoolean.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\AbstractBranchValueType' => $baseDir . '/sources/PropertyType/ValueType/Branch/AbstractBranchValueType.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeChoice' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeChoice.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypeCollection' => $baseDir . '/sources/PropertyType/ValueType/Branch/ValueTypeCollection.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeChoiceFromInput' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeChoiceFromInput.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypePropertyTree' => $baseDir . '/sources/PropertyType/ValueType/Branch/ValueTypePropertyTree.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClass' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeClass.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\AbstractLeafValueType' => $baseDir . '/sources/PropertyType/ValueType/Leaf/AbstractLeafValueType.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttribute' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeClassAttribute.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeAggregateFunction' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeAggregateFunction.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttributeGroupBy' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeClassAttributeGroupBy.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeBoolean' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeBoolean.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttributeValue' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeClassAttributeValue.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeChoice' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeChoice.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeCollection' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeCollection.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeChoiceFromInput' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeChoiceFromInput.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeFactory' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeFactory.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClass' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeClass.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeIcon' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeIcon.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttribute' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttribute.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeInteger' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeInteger.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttributeGroupBy' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttributeGroupBy.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeLabel' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeLabel.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttributeValue' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttributeValue.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeOQL' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeOQL.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeCollectionOfValues' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeCollectionOfValues.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeProfileName' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeProfileName.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeIcon' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeIcon.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeString' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeString.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeInteger' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeInteger.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeText' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeText.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\\BlockRenderer' => $baseDir . '/sources/Renderer/BlockRenderer.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => $baseDir . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php', 'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => $baseDir . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => $baseDir . '/sources/Renderer/Bootstrap/BsFormRenderer.php', 'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => $baseDir . '/sources/Renderer/Bootstrap/BsFormRenderer.php',
@@ -3932,5 +3935,5 @@ return array(
'privUITransactionFile' => $baseDir . '/application/transaction.class.inc.php', 'privUITransactionFile' => $baseDir . '/application/transaction.class.inc.php',
'privUITransactionSession' => $baseDir . '/application/transaction.class.inc.php', 'privUITransactionSession' => $baseDir . '/application/transaction.class.inc.php',
'utils' => $baseDir . '/application/utils.inc.php', 'utils' => $baseDir . '/application/utils.inc.php',
'<EFBFBD>' => $vendorDir . '/symfony/cache/Traits/ValueWrapper.php', '©' => $vendorDir . '/symfony/cache/Traits/ValueWrapper.php',
); );

View File

@@ -62,7 +62,7 @@ return array(
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'), 'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'), 'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'),
'Pelago\\Emogrifier\\' => array($vendorDir . '/pelago/emogrifier/src'), '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\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),

View File

@@ -345,8 +345,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
), ),
'League\\OAuth2\\Client\\' => 'League\\OAuth2\\Client\\' =>
array ( array (
0 => __DIR__ . '/..' . '/league/oauth2-client/src', 0 => __DIR__ . '/..' . '/league/oauth2-google/src',
1 => __DIR__ . '/..' . '/league/oauth2-google/src', 1 => __DIR__ . '/..' . '/league/oauth2-client/src',
), ),
'GuzzleHttp\\Psr7\\' => 'GuzzleHttp\\Psr7\\' =>
array ( array (
@@ -893,8 +893,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Forms\\Block\\FormBlockHelper' => __DIR__ . '/../..' . '/sources/Forms/Block/FormBlockHelper.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\\FormBlockService' => __DIR__ . '/../..' . '/sources/Forms/Block/FormBlockService.php',
'Combodo\\iTop\\Forms\\Block\\IFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/IFormBlock.php', 'Combodo\\iTop\\Forms\\Block\\IFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/IFormBlock.php',
'Combodo\\iTop\\Forms\\Compiler\\FormsCompiler' => __DIR__ . '/../..' . '/sources/Forms/Compiler/FormsCompiler.php',
'Combodo\\iTop\\Forms\\Compiler\\FormsCompilerException' => __DIR__ . '/../..' . '/sources/Forms/Compiler/FormsCompilerException.php',
'Combodo\\iTop\\Forms\\Controller\\FormsController' => __DIR__ . '/../..' . '/sources/Forms/Controller/FormsController.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\\DependencyHandler' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/DependencyHandler.php',
'Combodo\\iTop\\Forms\\FormBuilder\\DependencyMap' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/DependencyMap.php', 'Combodo\\iTop\\Forms\\FormBuilder\\DependencyMap' => __DIR__ . '/../..' . '/sources/Forms/FormBuilder/DependencyMap.php',
@@ -937,30 +935,35 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Forms\\Validator\\AttributeExist' => __DIR__ . '/../..' . '/sources/Forms/Validator/AttributeExist.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\\Forms\\Validator\\AttributeExistValidator' => __DIR__ . '/../..' . '/sources/Forms/Validator/AttributeExistValidator.php',
'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php', 'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php',
'Combodo\\iTop\\PropertyTree\\AbstractProperty' => __DIR__ . '/../..' . '/sources/PropertyTree/AbstractProperty.php', 'Combodo\\iTop\\PropertyType\\Compiler\\PropertyTypeCompiler' => __DIR__ . '/../..' . '/sources/PropertyType/Compiler/PropertyTypeCompiler.php',
'Combodo\\iTop\\PropertyTree\\Property' => __DIR__ . '/../..' . '/sources/PropertyTree/Property.php', 'Combodo\\iTop\\PropertyType\\Compiler\\PropertyTypeCompilerException' => __DIR__ . '/../..' . '/sources/PropertyType/Compiler/PropertyTypeCompilerException.php',
'Combodo\\iTop\\PropertyTree\\PropertyTree' => __DIR__ . '/../..' . '/sources/PropertyTree/PropertyTree.php', 'Combodo\\iTop\\PropertyType\\PropertyType' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyType.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeDesign' => __DIR__ . '/../..' . '/sources/PropertyTree/PropertyTreeDesign.php', 'Combodo\\iTop\\PropertyType\\PropertyTypeDesign' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyTypeDesign.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeException' => __DIR__ . '/../..' . '/sources/PropertyTree/PropertyTreeException.php', 'Combodo\\iTop\\PropertyType\\PropertyTypeException' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyTypeException.php',
'Combodo\\iTop\\PropertyTree\\PropertyTreeFactory' => __DIR__ . '/../..' . '/sources/PropertyTree/PropertyTreeFactory.php', 'Combodo\\iTop\\PropertyType\\PropertyTypeFactory' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyTypeFactory.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\AbstractValueType' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/AbstractValueType.php', 'Combodo\\iTop\\PropertyType\\PropertyTypeService' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyTypeService.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeAggregateFunction' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeAggregateFunction.php', 'Combodo\\iTop\\PropertyType\\ValueType\\AbstractValueType' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/AbstractValueType.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeBoolean' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeBoolean.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\AbstractBranchValueType' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/AbstractBranchValueType.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeChoice' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeChoice.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypeCollection' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/ValueTypeCollection.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeChoiceFromInput' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeChoiceFromInput.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypePropertyTree' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/ValueTypePropertyTree.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClass' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeClass.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\AbstractLeafValueType' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/AbstractLeafValueType.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttribute' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeClassAttribute.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeAggregateFunction' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeAggregateFunction.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttributeGroupBy' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeClassAttributeGroupBy.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeBoolean' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeBoolean.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeClassAttributeValue' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeClassAttributeValue.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeChoice' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeChoice.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeCollection' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeCollection.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeChoiceFromInput' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeChoiceFromInput.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeFactory' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeFactory.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClass' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeClass.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeIcon' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeIcon.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttribute' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttribute.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeInteger' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeInteger.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttributeGroupBy' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttributeGroupBy.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeLabel' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeLabel.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeClassAttributeValue' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeClassAttributeValue.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeOQL' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeOQL.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeCollectionOfValues' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeCollectionOfValues.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeProfileName' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeProfileName.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeIcon' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeIcon.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeString' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeString.php', 'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeInteger' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeInteger.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeText' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeText.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\\BlockRenderer' => __DIR__ . '/../..' . '/sources/Renderer/BlockRenderer.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php', 'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFormRenderer.php', 'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFormRenderer.php',
@@ -4318,7 +4321,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'privUITransactionFile' => __DIR__ . '/../..' . '/application/transaction.class.inc.php', 'privUITransactionFile' => __DIR__ . '/../..' . '/application/transaction.class.inc.php',
'privUITransactionSession' => __DIR__ . '/../..' . '/application/transaction.class.inc.php', 'privUITransactionSession' => __DIR__ . '/../..' . '/application/transaction.class.inc.php',
'utils' => __DIR__ . '/../..' . '/application/utils.inc.php', 'utils' => __DIR__ . '/../..' . '/application/utils.inc.php',
'<EFBFBD>' => __DIR__ . '/..' . '/symfony/cache/Traits/ValueWrapper.php', '©' => __DIR__ . '/..' . '/symfony/cache/Traits/ValueWrapper.php',
); );
public static function getInitializer(ClassLoader $loader) public static function getInitializer(ClassLoader $loader)

View File

@@ -36,8 +36,7 @@ if ($issues) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
} }
} }
trigger_error( throw new \RuntimeException(
'Composer detected issues in your platform: ' . implode(' ', $issues), 'Composer detected issues in your platform: ' . implode(' ', $issues)
E_USER_ERROR
); );
} }

View File

@@ -23,7 +23,7 @@ use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\Page; use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\DesignElement; use Combodo\iTop\DesignElement;
use Combodo\iTop\DesignDocument; use Combodo\iTop\DesignDocument;
use Combodo\iTop\PropertyTree\PropertyTreeDesign; use Combodo\iTop\PropertyType\PropertyTypeDesign;
require_once(APPROOT.'setup/setuputils.class.inc.php'); require_once(APPROOT.'setup/setuputils.class.inc.php');
require_once(APPROOT.'setup/modelfactory.class.inc.php'); require_once(APPROOT.'setup/modelfactory.class.inc.php');
@@ -700,9 +700,9 @@ PHP;
$oModuleDesignsNode = $this->oFactory->GetNodes('/itop_design/module_designs')->item(0); $oModuleDesignsNode = $this->oFactory->GetNodes('/itop_design/module_designs')->item(0);
$this->CompileModuleDesigns($oModuleDesignsNode, $sTempTargetDir, $sFinalTargetDir); $this->CompileModuleDesigns($oModuleDesignsNode, $sTempTargetDir, $sFinalTargetDir);
// Create property trees XML files // Create property types XML files
$oPropertyTreesNode = $this->oFactory->GetNodes('/itop_design/meta/property_trees')->item(0); $oPropertyTypesNode = $this->oFactory->GetNodes('/itop_design/meta/property_types')->item(0);
$this->CompilePropertyTrees($oPropertyTreesNode, $sTempTargetDir, $sFinalTargetDir); $this->CompilePropertyTypes($oPropertyTypesNode, $sTempTargetDir, $sFinalTargetDir);
// Compile the XML parameters // Compile the XML parameters
/** @var \MFElement $oParametersNode */ /** @var \MFElement $oParametersNode */
@@ -3577,17 +3577,17 @@ EOF;
} }
} }
protected function CompilePropertyTrees(?DOMNode $oPropertyTrees, string $sTempTargetDir, string $sFinalTargetDir): void protected function CompilePropertyTypes(?DOMNode $oPropertyTypes, string $sTempTargetDir, string $sFinalTargetDir): void
{ {
if ($oPropertyTrees) { if ($oPropertyTypes) {
foreach ($oPropertyTrees->GetNodes('property_tree') as $oPropertyTree) { foreach ($oPropertyTypes->GetNodes('property_type') as $oPropertyType) {
$oDoc = new PropertyTreeDesign(); $oDoc = new PropertyTypeDesign();
$oClone = $oDoc->importNode($oPropertyTree->cloneNode(true), true); $oClone = $oDoc->importNode($oPropertyType->cloneNode(true), true);
$oDoc->appendChild($oClone); $oDoc->appendChild($oClone);
/** @var DesignElement $oPropertyTree */ /** @var DesignElement $oPropertyType */
$sExtends = $oPropertyTree->GetChildText('extends', 'Default'); $sExtends = $oPropertyType->GetChildText('extends', 'Default');
SetupUtils::builddir($sTempTargetDir.'/core/property_trees/'.$sExtends); SetupUtils::builddir($sTempTargetDir.'/core/property_types/'.$sExtends);
$oDoc->save($sTempTargetDir.'/core/property_trees/'.$sExtends.'/'.$oPropertyTree->getAttribute('id').'.xml'); $oDoc->save($sTempTargetDir.'/core/property_types/'.$sExtends.'/'.$oPropertyType->getAttribute('id').'.xml');
} }
} }
} }

View File

@@ -94,18 +94,7 @@ class AttributeChoiceFormBlock extends ChoiceFormBlock
public static function ListAttributeCodesByCategory(string $sClass, string $sCategory = ''): array public static function ListAttributeCodesByCategory(string $sClass, string $sCategory = ''): array
{ {
$oModelReflection = ServiceLocator::GetInstance()->get('ModelReflection'); $oModelReflection = ServiceLocator::GetInstance()->get('ModelReflection');
$aAttributeCodes = []; $aNonGroupableAttributes = [
switch ($sCategory) {
case 'numeric':
foreach ($oModelReflection->ListAttributes($sClass, 'AttributeDecimal,AttributeDuration,AttributeInteger,AttributePercentage,AttributeSubItem') as $sAttCode => $sAttType) {
$sLabel = $oModelReflection->GetLabel($sClass, $sAttCode);
$aAttributeCodes[$sLabel] = $sAttCode;
}
break;
case 'groupable':
$aForbiddenAttType = [
'AttributeLinkedSet', 'AttributeLinkedSet',
'AttributeFriendlyName', 'AttributeFriendlyName',
'iAttributeNoGroupBy', //we cannot only use iAttributeNoGroupBy since this method is also used by the designer who do not have access to the classes' PHP reflection API. So the known classes has to be listed altogether 'iAttributeNoGroupBy', //we cannot only use iAttributeNoGroupBy since this method is also used by the designer who do not have access to the classes' PHP reflection API. So the known classes has to be listed altogether
@@ -113,41 +102,75 @@ class AttributeChoiceFormBlock extends ChoiceFormBlock
'AttributeEncryptedString', 'AttributeEncryptedString',
'AttributePassword', 'AttributePassword',
]; ];
$aAttributeCodes = [];
foreach ($oModelReflection->ListAttributes($sClass) as $sAttCode => $sAttType) { foreach ($oModelReflection->ListAttributes($sClass) as $sAttCode => $sAttType) {
foreach ($aForbiddenAttType as $sForbiddenAttType) {
if (is_a($sAttType, $sForbiddenAttType, true)) {
continue 2;
}
}
$sLabel = $oModelReflection->GetLabel($sClass, $sAttCode); $sLabel = $oModelReflection->GetLabel($sClass, $sAttCode);
// For external fields, find the real type of the target
$sExtFieldAttCode = $sAttCode;
$sTargetClass = $sClass;
while (is_a($sAttType, 'AttributeExternalField', true)) {
$sExtKeyAttCode = $oModelReflection->GetAttributeProperty($sTargetClass, $sExtFieldAttCode, 'extkey_attcode');
$sTargetAttCode = $oModelReflection->GetAttributeProperty($sTargetClass, $sExtFieldAttCode, 'target_attcode');
$sTargetClass = $oModelReflection->GetAttributeProperty($sTargetClass, $sExtKeyAttCode, 'targetclass');
$aTargetAttCodes = $oModelReflection->ListAttributes($sTargetClass);
$sAttType = $aTargetAttCodes[$sTargetAttCode];
$sExtFieldAttCode = $sTargetAttCode;
}
switch ($sCategory) {
case 'numeric':
if (is_a($sAttType, 'AttributeDecimal', true) ||
is_a($sAttType, 'AttributeDuration', true) ||
is_a($sAttType, 'AttributeInteger', true) ||
is_a($sAttType, 'AttributePercentage', true) ||
is_a($sAttType, 'AttributeSubItem', true)) {
$aAttributeCodes[$sLabel] = $sAttCode; $aAttributeCodes[$sLabel] = $sAttCode;
} }
break; break;
case 'enum': case 'groupable':
foreach ($oModelReflection->ListAttributes($sClass) as $sAttCode => $sAttType) { foreach ($aNonGroupableAttributes as $sNonGroupableAttribute) {
if (is_a($sAttType, 'AttributeEnum', true)) { if (is_a($sAttType, $sNonGroupableAttribute, true)) {
$sLabel = $oModelReflection->GetLabel($sClass, $sAttCode); break;
$aAttributeCodes[$sLabel] = $sAttCode;
} }
} }
$aAttributeCodes[$sLabel] = $sAttCode;
break;
case 'enum':
if (is_a($sAttType, 'AttributeEnum', true)) {
$aAttributeCodes[$sLabel] = $sAttCode;
}
break; break;
case 'date': case 'date':
foreach ($oModelReflection->ListAttributes($sClass) as $sAttCode => $sAttType) {
if (is_a($sAttType, 'AttributeDateTime', true)) { if (is_a($sAttType, 'AttributeDateTime', true)) {
$sLabel = $oModelReflection->GetLabel($sClass, $sAttCode);
$aAttributeCodes[$sLabel] = $sAttCode; $aAttributeCodes[$sLabel] = $sAttCode;
} }
}
break; break;
case '': case 'link':
foreach ($oModelReflection->ListAttributes($sClass) as $sAttCode => $sAttType) { if (is_a($sAttType, 'AttributeLinkedSet', true) ||
$sLabel = $oModelReflection->GetLabel($sClass, $sAttCode); is_a($sAttType, 'AttributeLinkedSetIndirect', true) ||
is_a($sAttType, 'AttributeExternalKey', true) ||
is_a($sAttType, 'AttributeHierarchicalKey', true)) {
$aAttributeCodes[$sLabel] = $sAttCode; $aAttributeCodes[$sLabel] = $sAttCode;
} }
break; break;
case 'string':
if (is_a($sAttType, 'AttributeString', true)) {
$aAttributeCodes[$sLabel] = $sAttCode;
}
break;
case 'all':
case '':
$aAttributeCodes[$sLabel] = $sAttCode;
break;
}
} }
return $aAttributeCodes; return $aAttributeCodes;

View File

@@ -32,7 +32,6 @@ class AttributeValueChoiceFormBlock extends ChoiceFormBlock
protected function RegisterOptions(OptionsRegister $oOptionsRegister): void protected function RegisterOptions(OptionsRegister $oOptionsRegister): void
{ {
parent::RegisterOptions($oOptionsRegister); parent::RegisterOptions($oOptionsRegister);
$oOptionsRegister->SetOption('multiple', true);
$oOptionsRegister->SetOptionArrayValue('attr', 'size', 5); $oOptionsRegister->SetOptionArrayValue('attr', 'size', 5);
$oOptionsRegister->SetOptionArrayValue('attr', 'style', 'height: auto;'); $oOptionsRegister->SetOptionArrayValue('attr', 'style', 'height: auto;');
} }

View File

@@ -8,7 +8,8 @@
namespace Combodo\iTop\Forms\Block; namespace Combodo\iTop\Forms\Block;
use Combodo\iTop\Forms\Block\Base\FormBlock; use Combodo\iTop\Forms\Block\Base\FormBlock;
use Combodo\iTop\Forms\Compiler\FormsCompiler; use Combodo\iTop\PropertyType\Compiler\PropertyTypeCompiler;
use Combodo\iTop\PropertyType\PropertyTypeService;
use Combodo\iTop\Service\Cache\DataModelDependantCache; use Combodo\iTop\Service\Cache\DataModelDependantCache;
use Combodo\iTop\Service\DependencyInjection\ServiceLocator; use Combodo\iTop\Service\DependencyInjection\ServiceLocator;
use ModelReflection; use ModelReflection;
@@ -17,14 +18,11 @@ use utils;
class FormBlockService class FormBlockService
{ {
public const CACHE_POOL = 'Forms';
private static FormBlockService $oInstance; private static FormBlockService $oInstance;
private DataModelDependantCache $oCacheService;
protected function __construct(ModelReflection $oModelReflection = null) protected function __construct(ModelReflection $oModelReflection = null)
{ {
ServiceLocator::GetInstance()->RegisterService('ModelReflection', $oModelReflection ?? new ModelReflectionRuntime()); ServiceLocator::GetInstance()->RegisterService('ModelReflection', $oModelReflection ?? new ModelReflectionRuntime());
$this->oCacheService = DataModelDependantCache::GetInstance();
} }
final public static function GetInstance(ModelReflection $oModelReflection = null): FormBlockService final public static function GetInstance(ModelReflection $oModelReflection = null): FormBlockService
@@ -42,26 +40,13 @@ class FormBlockService
* *
* @return \Combodo\iTop\Forms\Block\Base\FormBlock * @return \Combodo\iTop\Forms\Block\Base\FormBlock
* @throws \Combodo\iTop\Forms\Block\FormBlockException * @throws \Combodo\iTop\Forms\Block\FormBlockException
* @throws \Combodo\iTop\Forms\Compiler\FormsCompilerException * @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException * @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException * @throws \DOMFormatException
*/ */
public function GetFormBlockById(string $sId, string $sType): FormBlock public function GetFormBlockById(string $sId, string $sType): FormBlock
{ {
$sFilteredId = preg_replace('/[^0-9a-zA-Z_]/', '', $sId); return PropertyTypeService::GetInstance()->GetFormBlockById($sId, $sType);
if (strlen($sFilteredId) === 0 || $sFilteredId !== $sId) {
throw new FormBlockException('Malformed name for block: '.json_encode($sId));
}
$sCacheKey = $sType.'/'.$sFilteredId;
if (!$this->oCacheService->HasEntry(self::CACHE_POOL, $sCacheKey) || utils::IsDevelopmentEnvironment()) {
// Cache not found, compile the form
$sPHPContent = FormsCompiler::GetInstance()->CompileForm($sFilteredId, $sType);
$this->oCacheService->StorePhpContent(FormBlockService::CACHE_POOL, $sCacheKey, "<?php\n\n$sPHPContent");
}
$this->oCacheService->FetchPHP(self::CACHE_POOL, $sCacheKey);
$sFormBlockClass = 'FormFor__'.$sFilteredId;
return new $sFormBlockClass($sFilteredId);
} }
} }

View File

@@ -1,90 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Forms\Compiler;
use Combodo\iTop\DesignDocument;
use Combodo\iTop\Forms\Block\Base\FormBlock;
use Combodo\iTop\Forms\Block\FormBlockService;
use Combodo\iTop\PropertyTree\PropertyTreeFactory;
use Combodo\iTop\Service\Cache\DataModelDependantCache;
use DOMFormatException;
use utils;
/**
* XML to PHP Forms compiler.
*
* @package Combodo\iTop\Forms\Compiler
* @since 3.3.0
*/
class FormsCompiler
{
private static FormsCompiler $oInstance;
private DataModelDependantCache $oCacheService;
protected function __construct()
{
$this->oCacheService = DataModelDependantCache::GetInstance();
}
final public static function GetInstance(): FormsCompiler
{
if (!isset(static::$oInstance)) {
static::$oInstance = new FormsCompiler();
}
return static::$oInstance;
}
/**
* Compile XML property tree into PHP to create the configuration form
*
* @param string $sXMLContent property tree structure in xml
*
* @return string Generated PHP
* @throws \Combodo\iTop\Forms\Compiler\FormsCompilerException
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
* @throws \DOMFormatException
*/
public function CompileFormFromXML(string $sXMLContent): string
{
$oDoc = new DesignDocument();
libxml_clear_errors();
$oDoc->loadXML($sXMLContent);
$aErrors = libxml_get_errors();
if (count($aErrors) > 0) {
throw new FormsCompilerException('Dashlet properties definition not correctly formatted!');
}
/** @var \Combodo\iTop\DesignElement $oRoot */
$oRoot = $oDoc->firstChild;
$oPropertyTree = PropertyTreeFactory::GetInstance()->CreateTreeFromDom($oRoot);
return $oPropertyTree->ToPHPFormBlock();
}
/**
* @param string $sId
* @param string $sType
*
* @return string Generated PHP
* @throws \Combodo\iTop\Forms\Compiler\FormsCompilerException
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
* @throws \DOMFormatException
*/
public function CompileForm(string $sId, string $sType): string
{
$sPath = utils::GetAbsoluteModulePath('core')."property_trees/$sType/$sId.xml";
if (!file_exists($sPath)) {
throw new FormsCompilerException("Properties definition $sType/$sId not present");
}
$sXMLContent = file_get_contents($sPath);
return $this->CompileFormFromXML($sXMLContent);
}
}

View File

@@ -1,14 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Forms\Compiler;
use Combodo\iTop\Forms\FormsException;
class FormsCompilerException extends FormsException
{
}

View File

@@ -9,6 +9,9 @@ namespace Combodo\iTop\Forms\IO;
use Combodo\iTop\Forms\Block\AbstractFormBlock; use Combodo\iTop\Forms\Block\AbstractFormBlock;
use Combodo\iTop\Forms\IO\Format\AbstractIOFormat; use Combodo\iTop\Forms\IO\Format\AbstractIOFormat;
use Combodo\iTop\Forms\IO\Format\AttributeIOFormat;
use Combodo\iTop\Forms\IO\Format\ClassIOFormat;
use Combodo\iTop\Forms\IO\Format\StringIOFormat;
use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormEvents;
/** /**
@@ -312,4 +315,26 @@ class AbstractFormIO
return $this->aBindingsToInputs; return $this->aBindingsToInputs;
} }
/**
* Compatibility rules
*
* @param \Combodo\iTop\Forms\IO\AbstractFormIO $oFormIO
*
* @return bool
*/
public function IsCompatibleWith(AbstractFormIO $oFormIO): bool
{
if ($this->GetDataType() === StringIOFormat::class) {
switch ($oFormIO->GetDataType()) {
case StringIOFormat::class:
case AttributeIOFormat::class:
case ClassIOFormat::class:
return true;
default:
return false;
}
}
return ($oFormIO->GetDataType() === $this->GetDataType());
}
} }

View File

@@ -29,7 +29,7 @@ class FormBinding
// Check IOFormat validity // Check IOFormat validity
$sSourceDataType = $oSourceIO->GetDataType(); $sSourceDataType = $oSourceIO->GetDataType();
$sDestinationDataType = $oDestinationIO->GetDataType(); $sDestinationDataType = $oDestinationIO->GetDataType();
if ($sSourceDataType !== $sDestinationDataType) { if (!$oDestinationIO->IsCompatibleWith($oSourceIO)) {
throw new FormBlockIOException('binding '.json_encode($sSourceDataType).' to '.json_encode($sDestinationDataType).' is not supported'); throw new FormBlockIOException('binding '.json_encode($sSourceDataType).' to '.json_encode($sDestinationDataType).' is not supported');
} }
$this->oDestinationIO = $oDestinationIO; $this->oDestinationIO = $oDestinationIO;

View File

@@ -1,86 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyTree;
use Combodo\iTop\DesignElement;
use Combodo\iTop\PropertyTree\ValueType\AbstractValueType;
/**
* @since 3.3.0
*/
abstract class AbstractProperty
{
protected ?AbstractProperty $oParent;
protected string $sId;
protected ?string $sLabel;
/** @var array<AbstractProperty> */
protected array $aChildren = [];
protected ?AbstractValueType $oValueType;
protected ?string $sIdWithPath;
/**
* Init property tree node from xml dom node
*
* @param \Combodo\iTop\DesignElement $oDomNode
* @param string $sParentId
*
* @return void
* @throws \DOMFormatException
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
*/
public function InitFromDomNode(DesignElement $oDomNode, ?AbstractProperty $oParent = null): void
{
$this->oParent = $oParent;
$this->sId = $oDomNode->getAttribute('id');
if (is_null($oParent)) {
$this->sIdWithPath = $this->sId;
} else {
$this->sIdWithPath = $oParent->sIdWithPath.'__'.$this->sId;
}
$this->sLabel = $oDomNode->GetChildText('label');
}
abstract public function ToPHPFormBlock(array &$aPHPFragments = []): string;
public function GetValueType(): ?AbstractValueType
{
return $this->oValueType;
}
public function AddChild(AbstractProperty $oValueType): void
{
$this->aChildren[] = $oValueType;
}
public function GetChildren(): array
{
return $this->aChildren;
}
public function GetSibling(string $sId): ?AbstractProperty
{
if (is_null($this->oParent)) {
return null;
}
foreach ($this->oParent->GetChildren() as $oSibling) {
if ($oSibling->sId == $sId) {
return $oSibling;
}
}
return null;
}
public function GetIdWithPath(): ?string
{
return $this->sIdWithPath;
}
}

View File

@@ -1,155 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyTree;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\Expression\BooleanExpressionFormBlock;
use Combodo\iTop\Forms\Block\Expression\NumberExpressionFormBlock;
use Combodo\iTop\Forms\Block\Expression\StringExpressionFormBlock;
use Combodo\iTop\Forms\IO\Format\BooleanIOFormat;
use Combodo\iTop\Forms\IO\Format\ClassIOFormat;
use Combodo\iTop\Forms\IO\Format\NumberIOFormat;
use Combodo\iTop\Forms\IO\Format\StringIOFormat;
use Combodo\iTop\PropertyTree\ValueType\ValueTypeFactory;
use Exception;
use Expression;
use utils;
/**
* @since 3.3.0
*/
class Property extends AbstractProperty
{
private ?string $sRelevanceCondition = null;
/**
* @inheritDoc
*/
public function InitFromDomNode(DesignElement $oDomNode, ?AbstractProperty $oParent = null): void
{
parent::InitFromDomNode($oDomNode, $oParent);
$oValueTypeNode = $oDomNode->GetOptionalElement('value-type');
if ($oValueTypeNode) {
$this->oValueType = ValueTypeFactory::GetInstance()->CreateValueTypeFromDomNode($oValueTypeNode, $this);
} else {
throw new PropertyTreeException("Node: {$this->sId}, missing value-type in node specification");
}
$this->sRelevanceCondition = $oDomNode->GetChildText('relevance-condition');
}
/**
* @param $aPHPFragments
*
* @return string
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
*/
public function ToPHPFormBlock(array &$aPHPFragments = []): string
{
$sFormBlockClass = $this->oValueType->GetFormBlockClass();
$sInputs = '';
$sPrerequisiteExpressions = '';
if (!is_null($this->sRelevanceCondition)) {
$this->GenerateInputs('visible', $this->sRelevanceCondition, $sPrerequisiteExpressions, $sInputs);
}
foreach ($this->oValueType->GetInputValues() as $sInputName => $sValue) {
$this->GenerateInputs($sInputName, $sValue, $sPrerequisiteExpressions, $sInputs);
}
foreach ($this->oValueType->GetDynamicInputValues() as $sInputName => $sValue) {
$this->GenerateInputs($sInputName, $sValue, $sPrerequisiteExpressions, $sInputs, true);
}
$sLabel = utils::QuoteForPHP($this->sLabel);
$aOptions = [
'label' => $sLabel,
];
$aOptions += $this->oValueType->GetFormBlockOptions();
$sOptions = '';
foreach ($aOptions as $sOption => $sValue) {
$sOptions .= "\t\t\t".utils::QuoteForPHP($sOption)." => $sValue,\n";
}
$this->oValueType->UpdatePHPFragmentsList($aPHPFragments);
return <<<PHP
{$sPrerequisiteExpressions}\$this->Add('$this->sId', '$sFormBlockClass', [
$sOptions\t\t]){$sInputs};
PHP;
}
private function GenerateInputs(string $sInputName, string $sValue, string &$sPrerequisiteExpressions, string &$sInputs, bool $bIsDynamic = false): void
{
if (preg_match('/^{{(?<node>\w+)\.(?<output>\w+)}}$/', $sValue, $aMatches) === 1) {
$sVerb = $bIsDynamic ? 'AddInputDependsOn' : 'InputDependsOn';
$sInputs .= "\n ->$sVerb('$sInputName', '{$aMatches['node']}', '{$aMatches['output']}')";
} elseif (preg_match('/^{{(?<expression>.*)}}$/', $sValue, $aMatches) === 1) {
$sExpression = $aMatches['expression'];
$sBindings = '';
try {
$oExpression = Expression::FromOQL($sExpression);
} catch (Exception $e) {
throw new PropertyTreeException("Node: {$this->sId}, invalid syntax in condition: ".$e->getMessage());
}
$aFieldsToResolve = array_unique($oExpression->ListRequiredFields());
foreach ($aFieldsToResolve as $sFieldToResolve) {
if (preg_match('/(?<node>\w+)\.(?<output>\w+)/', $sFieldToResolve, $aMatches) === 1) {
$sNode = $aMatches['node'];
$oSibling = $this->GetSibling($sNode);
if (is_null($oSibling)) {
// Search in collection
if (is_a($this->oParent?->oValueType ?? null, 'Combodo-ValueType-Collection')) {
$bSourceNodeFound = false;
$aSiblings = $this->oParent->oValueType->GetChildren();
foreach ($aSiblings as $oSibling) {
if ($oSibling->sId == $sNode) {
$bSourceNodeFound = true;
break;
}
}
if (!$bSourceNodeFound) {
throw new PropertyTreeException("node: {$this->sId}, source: $sNode not found in collection: {$this->oParent->sId}");
}
} else {
throw new PropertyTreeException("Node: {$this->sId}, invalid source in condition: $sNode");
}
}
$sOutput = $aMatches['output'];
if (!in_array($sOutput, $oSibling->oValueType->GetOutputs())) {
throw new PropertyTreeException("Node: {$this->sId}, invalid output in condition: $sFieldToResolve");
}
$sBindings .= "\n ->AddInputDependsOn('{$sNode}.$sOutput', '$sNode', '$sOutput')";
} else {
throw new PropertyTreeException("Node: {$this->sId}, missing output or source in condition: $sFieldToResolve");
}
}
$sExpressionClass = match ($this->oValueType->GetInputType($sInputName)) {
BooleanIOFormat::class => BooleanExpressionFormBlock::class,
StringIOFormat::class, ClassIOFormat::class => StringExpressionFormBlock::class,
NumberIOFormat::class => NumberExpressionFormBlock::class,
default => throw new PropertyTreeException("Node: {$this->sId}, unsupported expression for input type: $sInputName"),
};
$sExpression = utils::QuoteForPHP($sExpression);
$sPrerequisiteExpressions = <<<PHP
\$this->Add('{$this->sId}_{$sInputName}_expression', '$sExpressionClass', [
'expression' => $sExpression,
]){$sBindings};
PHP;
$sVerb = $bIsDynamic ? 'AddInputDependsOn' : 'InputDependsOn';
$sInputs .= "\n ->$sVerb('$sInputName', '{$this->sId}_{$sInputName}_expression', 'result')";
} else {
$sInputs .= "\n ->SetInputValue('$sInputName', ".utils::QuoteForPHP($sValue).")";
}
}
}

View File

@@ -1,65 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyTree;
use Combodo\iTop\DesignElement;
/**
* @since 3.3.0
*/
class PropertyTree extends AbstractProperty
{
/**
* @inheritdoc
*/
public function InitFromDomNode(DesignElement $oDomNode, ?AbstractProperty $oParent = null): void
{
parent::InitFromDomNode($oDomNode, $oParent);
$oPropertyTreeFactory = PropertyTreeFactory::GetInstance();
// read child properties
foreach ($oDomNode->GetUniqueElement('nodes')->childNodes as $oNode) {
if ($oNode instanceof DesignElement) {
$this->AddChild($oPropertyTreeFactory->CreateNodeFromDom($oNode, $this));
}
}
}
public function ToPHPFormBlock(array &$aPHPFragments = []): string
{
$bIsRoot = (count($aPHPFragments) === 0);
$sLocalPHP = <<<PHP
class FormFor__$this->sId extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
PHP;
foreach ($this->aChildren as $oProperty) {
$sLocalPHP .= "\n".$oProperty->ToPHPFormBlock($aPHPFragments);
}
$sLocalPHP .= <<<PHP
}
}
PHP;
$aPHPFragments[] = $sLocalPHP;
if ($bIsRoot) {
// $sOutputPHP = <<<PHP
//namespace Combodo\iTop\Forms\Block\Generated;
//
//PHP;
return implode("\n", $aPHPFragments);
}
return '';
}
}

View File

@@ -1,66 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyTree;
use Combodo\iTop\DesignDocument;
use Combodo\iTop\DesignElement;
class PropertyTreeFactory
{
private static PropertyTreeFactory $oInstance;
protected function __construct()
{
}
final public static function GetInstance(): PropertyTreeFactory
{
if (!isset(static::$oInstance)) {
static::$oInstance = new PropertyTreeFactory();
}
return static::$oInstance;
}
/**
* Create a property node from a design element
*
* @param \Combodo\iTop\DesignElement $oDomNode
* @param \Combodo\iTop\PropertyTree\AbstractProperty|null $oParent
*
* @return \Combodo\iTop\PropertyTree\AbstractProperty
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
* @throws \DOMFormatException
*/
public function CreateTreeFromDom(DesignElement $oDomNode, ?AbstractProperty $oParent = null): AbstractProperty
{
$oNode = new PropertyTree();
$oNode->InitFromDomNode($oDomNode, $oParent);
return $oNode;
}
/**
* Create a property node from a design element
*
* @param \Combodo\iTop\DesignElement $oDomNode
* @param \Combodo\iTop\PropertyTree\AbstractProperty|null $oParent
*
* @return \Combodo\iTop\PropertyTree\AbstractProperty
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
* @throws \DOMFormatException
*/
public function CreateNodeFromDom(DesignElement $oDomNode, ?AbstractProperty $oParent = null): AbstractProperty
{
// The class of the property tree node is given by the xsi:type attribute
$oNode = new Property();
$oNode->InitFromDomNode($oDomNode, $oParent);
return $oNode;
}
}

View File

@@ -1,81 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyTree\ValueType;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\IO\FormInput;
use Combodo\iTop\PropertyTree\AbstractProperty;
use utils;
/**
* @since 3.3.0
*/
abstract class AbstractValueType
{
abstract public function GetFormBlockClass(): string;
/** @var FormInput[] */
protected array $aInputs = [];
protected array $aOutputs = [];
protected array $aInputValues = [];
protected array $aDynamicInputValues = [];
protected array $aFormBlockOptionsForPHP = [];
/**
* @param \Combodo\iTop\DesignElement $oDomNode
* @param \Combodo\iTop\PropertyTree\AbstractProperty $oParent Parent node (used for trees)
*
* @return void
* @throws \DOMFormatException
*/
public function InitFromDomNode(DesignElement $oDomNode, AbstractProperty $oParent): void
{
$sBlockNodeClass = $this->GetFormBlockClass();
$oBlockNode = new $sBlockNodeClass('foo');
foreach ($oBlockNode->GetInputs() as $oInput) {
$sInputName = $oInput->GetName();
$this->aInputs[$sInputName] = $oInput;
$sInputValue = $oDomNode->GetChildText($sInputName);
if (utils::IsNotNullOrEmptyString($sInputValue)) {
$this->aInputValues[$sInputName] = $sInputValue;
}
}
foreach ($oBlockNode->GetOutputs() as $oOutput) {
$this->aOutputs[] = $oOutput->GetName();
}
}
public function GetFormBlockOptions(): array
{
return $this->aFormBlockOptionsForPHP;
}
public function GetInputValues(): array
{
return $this->aInputValues;
}
public function GetInputType(string $sInputName): string
{
return $this->aInputs[$sInputName]->GetDataType();
}
public function GetDynamicInputValues(): array
{
return $this->aDynamicInputValues;
}
public function GetOutputs(): array
{
return $this->aOutputs;
}
public function UpdatePHPFragmentsList(array &$aPHPFragments): void
{
}
}

View File

@@ -1,75 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyTree\ValueType;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\Base\CollectionBlock;
use Combodo\iTop\PropertyTree\AbstractProperty;
use Combodo\iTop\PropertyTree\PropertyTreeFactory;
use utils;
class ValueTypeCollection extends AbstractValueType
{
private array $aChildren = [];
private string $sSubTreeClass = '';
public function InitFromDomNode(DesignElement $oDomNode, AbstractProperty $oParent): void
{
parent::InitFromDomNode($oDomNode, $oParent);
$oPropertyTreeFactory = PropertyTreeFactory::GetInstance();
$this->aFormBlockOptionsForPHP['button_label'] = utils::QuoteForPHP('UI:AddSubTree');
$this->sSubTreeClass = 'SubFormFor__'.$oParent->GetIdWithPath();
$this->aFormBlockOptionsForPHP['block_entry_type'] = utils::QuoteForPHP($this->sSubTreeClass);
// read child properties
foreach ($oDomNode->GetUniqueElement('prototype')->childNodes as $oNode) {
if ($oNode instanceof DesignElement) {
$this->AddChild($oPropertyTreeFactory->CreateNodeFromDom($oNode, $oParent));
}
}
}
public function GetFormBlockClass(): string
{
return CollectionBlock::class;
}
public function AddChild(AbstractProperty $oValueType): void
{
$this->aChildren[] = $oValueType;
}
/**
* @return AbstractProperty[]
*/
public function GetChildren(): array
{
return $this->aChildren;
}
public function UpdatePHPFragmentsList(array &$aPHPFragments): void
{
$sSubClassPHP = <<<PHP
class $this->sSubTreeClass extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
PHP;
foreach ($this->GetChildren() as $oProperty) {
$sSubClassPHP .= "\n".$oProperty->ToPHPFormBlock($aPHPFragments);
}
$sSubClassPHP .= <<<PHP
}
}
PHP;
$aPHPFragments[] = $sSubClassPHP;
}
}

View File

@@ -0,0 +1,133 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType\Compiler;
use Combodo\iTop\DesignDocument;
use Combodo\iTop\PropertyType\PropertyType;
use Combodo\iTop\PropertyType\PropertyTypeFactory;
use utils;
/**
* XML to PHP Forms compiler.
*
* @package Combodo\iTop\PropertyType\Compiler
* @since 3.3.0
*/
class PropertyTypeCompiler
{
private static PropertyTypeCompiler $oInstance;
protected function __construct()
{
}
final public static function GetInstance(): PropertyTypeCompiler
{
if (!isset(static::$oInstance)) {
static::$oInstance = new PropertyTypeCompiler();
}
return static::$oInstance;
}
/**
* @param string $sXMLContent
*
* @return \Combodo\iTop\PropertyType\PropertyType
* @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException
*/
protected function CompilePropertyTypeFromXML(string $sXMLContent): PropertyType
{
$oDoc = new DesignDocument();
libxml_clear_errors();
$oDoc->loadXML($sXMLContent);
$aErrors = libxml_get_errors();
if (count($aErrors) > 0) {
throw new PropertyTypeCompilerException('Property types definition not correctly formatted!');
}
/** @var \Combodo\iTop\DesignElement $oRoot */
$oRoot = $oDoc->firstChild;
return PropertyTypeFactory::GetInstance()->CreatePropertyTypeFromDom($oRoot);
}
/**
* @param string $sId
* @param string $sType
*
* @return string
* @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
*/
protected function GetXMLContent(string $sId, string $sType): string
{
$sPath = utils::GetAbsoluteModulePath('core')."property_types/$sType/$sId.xml";
if (!file_exists($sPath)) {
throw new PropertyTypeCompilerException("Properties definition $sType/$sId not present");
}
return file_get_contents($sPath);
}
/**
* Compile XML property tree into PHP to create the configuration form
*
* @param string $sXMLContent property tree structure in xml
*
* @return string Generated PHP
* @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException
*/
public function CompileFormFromXML(string $sXMLContent): string
{
$oPropertyType = $this->CompilePropertyTypeFromXML($sXMLContent);
return $oPropertyType->ToPHPFormBlock();
}
/**
* @param string $sXMLContent
*
* @return string
* @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException
*/
public function CompileEntityFromXML(string $sXMLContent): string
{
$oPropertyType = $this->CompilePropertyTypeFromXML($sXMLContent);
return $oPropertyType->ToPHPEntity();
}
/**
* @param string $sId
* @param string $sType
*
* @return string Generated PHP
* @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException
*/
public function CompileForm(string $sId, string $sType): string
{
$sXMLContent = $this->GetXMLContent($sId, $sType);
return $this->CompileFormFromXML($sXMLContent);
}
public function CompileEntity(string $sId, string $sType): string
{
$sXMLContent = $this->GetXMLContent($sId, $sType);
return $this->CompileEntityFromXML($sXMLContent);
}
}

View File

@@ -0,0 +1,14 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType\Compiler;
use Combodo\iTop\PropertyType\PropertyTypeException;
class PropertyTypeCompilerException extends PropertyTypeException
{
}

View File

@@ -0,0 +1,79 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType;
use Combodo\iTop\DesignElement;
use Combodo\iTop\PropertyType\ValueType\AbstractValueType;
/**
* A property type is a definition of properties (organized in tree)
* used for dashlet for example.
* @since 3.3.0
*/
class PropertyType
{
private string $sParentType = '';
private string $sId;
private AbstractValueType $oValueType;
/**
* @param \Combodo\iTop\DesignElement $oDomNode
*
* @return void
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException
*/
public function InitFromDomNode(DesignElement $oDomNode): void
{
$this->sId = $oDomNode->getAttribute('id');
$this->sParentType = $oDomNode->GetChildText('extends', '');
$oDefinitionNode = $oDomNode->GetUniqueElement('definition');
$sDefinitionNodeType = $oDefinitionNode->getAttribute('xsi:type');
if (!is_a($sDefinitionNodeType, AbstractValueType::class, true)) {
throw new PropertyTypeException('Unsupported type '.json_encode($sDefinitionNodeType).' in ');
}
$this->oValueType = new $sDefinitionNodeType();
$this->oValueType->SetRootId($this->sId);
$this->oValueType->InitFromDomNode($oDefinitionNode);
}
public function ToPHPFormBlock(): string
{
$aPHPFragments = [];
if ($this->oValueType->IsLeaf()) {
$sLocalPHP = <<<PHP
class FormFor__$this->sId extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
PHP;
$sLocalPHP .= "\n".$this->oValueType->ToPHPFormBlock($aPHPFragments);
$sLocalPHP .= <<<PHP
}
}
PHP;
$aPHPFragments[] = $sLocalPHP;
} else {
$this->oValueType->ToPHPFormBlock($aPHPFragments);
}
return implode("\n\n", $aPHPFragments);
}
public function GetParentType(): string
{
return $this->sParentType;
}
}

View File

@@ -5,14 +5,18 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree; namespace Combodo\iTop\PropertyType;
use Combodo\iTop\DesignDocument; use Combodo\iTop\DesignDocument;
use Exception; use Exception;
use ReturnTypeWillChange; use ReturnTypeWillChange;
use utils; use utils;
class PropertyTreeDesign extends DesignDocument /**
* Load and save XML definitions of property types
* @since 3.3.0
*/
class PropertyTypeDesign extends DesignDocument
{ {
public function __construct(string $sDesignSourceId = null, string $sType = 'Default') public function __construct(string $sDesignSourceId = null, string $sType = 'Default')
{ {

View File

@@ -5,10 +5,13 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree; namespace Combodo\iTop\PropertyType;
use Exception; use Exception;
class PropertyTreeException extends Exception /**
* @since 3.3.0
*/
class PropertyTypeException extends Exception
{ {
} }

View File

@@ -0,0 +1,51 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType;
use Combodo\iTop\DesignElement;
use Combodo\iTop\PropertyType\ValueType\AbstractValueType;
/**
* Build a property type form XML DOM
* @since 3.3.0
*/
class PropertyTypeFactory
{
private static PropertyTypeFactory $oInstance;
protected function __construct()
{
}
final public static function GetInstance(): PropertyTypeFactory
{
if (!isset(static::$oInstance)) {
static::$oInstance = new PropertyTypeFactory();
}
return static::$oInstance;
}
/**
* Create a property node from a design element
*
* @param \Combodo\iTop\DesignElement $oDomNode
* @param \Combodo\iTop\PropertyType\ValueType\AbstractValueType|null $oParent
*
* @return \Combodo\iTop\PropertyType\PropertyType
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException
*/
public function CreatePropertyTypeFromDom(DesignElement $oDomNode, ?AbstractValueType $oParent = null): PropertyType
{
$oNode = new PropertyType();
$oNode->InitFromDomNode($oDomNode);
return $oNode;
}
}

View File

@@ -0,0 +1,91 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType;
use Combodo\iTop\Forms\Block\Base\FormBlock;
use Combodo\iTop\Forms\Block\FormBlockException;
use Combodo\iTop\Forms\Block\FormBlockService;
use Combodo\iTop\PropertyType\Compiler\PropertyTypeCompiler;
use Combodo\iTop\Service\Cache\DataModelDependantCache;
use utils;
class PropertyTypeService
{
public const FORM_CACHE_POOL = 'Forms';
private DataModelDependantCache $oCacheService;
private static PropertyTypeService $oInstance;
protected function __construct()
{
$this->oCacheService = DataModelDependantCache::GetInstance();
}
final public static function GetInstance(): PropertyTypeService
{
if (!isset(static::$oInstance)) {
static::$oInstance = new PropertyTypeService();
}
return static::$oInstance;
}
/**
* @param string $sId name of the form to retrieve
* @param string $sType
*
* @return \Combodo\iTop\Forms\Block\Base\FormBlock
* @throws \Combodo\iTop\Forms\Block\FormBlockException
* @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException
*/
public function GetFormBlockById(string $sId, string $sType): FormBlock
{
$sFilteredId = $this->SanitizeId($sId);
$sCacheKey = $this->GetCacheKey($sType, $sFilteredId);
if (!$this->oCacheService->HasEntry(self::FORM_CACHE_POOL, $sCacheKey) || utils::IsDevelopmentEnvironment()) {
// Cache not found, compile the form
$sPHPContent = PropertyTypeCompiler::GetInstance()->CompileForm($sFilteredId, $sType);
$this->oCacheService->StorePhpContent(self::FORM_CACHE_POOL, $sCacheKey, "<?php\n\n$sPHPContent");
}
$this->oCacheService->FetchPHP(self::FORM_CACHE_POOL, $sCacheKey);
$sFormBlockClass = 'FormFor__'.$sFilteredId;
return new $sFormBlockClass($sFilteredId);
}
/**
* @param string $sId
*
* @return string
* @throws \Combodo\iTop\Forms\Block\FormBlockException
*/
private function SanitizeId(string $sId): string
{
$sFilteredId = preg_replace('/[^0-9a-zA-Z_]/', '', $sId);
if (strlen($sFilteredId) === 0 || $sFilteredId !== $sId) {
throw new FormBlockException('Malformed name for block: '.json_encode($sId));
}
return $sFilteredId;
}
/**
* @param string $sType
* @param string $sFilteredId
*
* @return string
*/
private function GetCacheKey(string $sType, string $sFilteredId): string
{
return $sType.'/'.$sFilteredId;
}
}

View File

@@ -0,0 +1,231 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType\ValueType;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\Expression\BooleanExpressionFormBlock;
use Combodo\iTop\Forms\Block\Expression\NumberExpressionFormBlock;
use Combodo\iTop\Forms\Block\Expression\StringExpressionFormBlock;
use Combodo\iTop\Forms\IO\Format\BooleanIOFormat;
use Combodo\iTop\Forms\IO\Format\ClassIOFormat;
use Combodo\iTop\Forms\IO\Format\NumberIOFormat;
use Combodo\iTop\Forms\IO\Format\StringIOFormat;
use Combodo\iTop\Forms\IO\FormInput;
use Combodo\iTop\PropertyType\PropertyTypeException;
use Combodo\iTop\PropertyType\ValueType\Branch\AbstractBranchValueType;
use Combodo\iTop\PropertyType\ValueType\Branch\ValueTypePropertyTree;
use Exception;
use Expression;
use utils;
/**
* @since 3.3.0
*/
abstract class AbstractValueType
{
protected ?AbstractBranchValueType $oParent;
protected string $sIdWithPath;
/** @var FormInput[] */
protected array $aInputs = [];
protected array $aOutputs = [];
protected array $aInputValues = [];
protected array $aDynamicInputValues = [];
protected array $aFormBlockOptionsForPHP = [];
protected string $sId;
protected ?string $sRelevanceCondition = null;
protected ?string $sLabel;
abstract public function GetFormBlockClass(): string;
/**
* @param \Combodo\iTop\DesignElement $oDomNode
* @param \Combodo\iTop\PropertyType\ValueType\Branch\AbstractBranchValueType|null $oParent Parent node (used for trees)
*
* @return void
* @throws \DOMFormatException
*/
public function InitFromDomNode(DesignElement $oDomNode, ?AbstractBranchValueType $oParent = null): void
{
$this->oParent = $oParent;
// id can already be set for the definition root node
$this->sId = $this->sId ?? $oDomNode->getAttribute('id');
if (is_null($oParent)) {
$this->sIdWithPath = $this->sId;
} else {
$this->sIdWithPath = $oParent->sIdWithPath.'__'.$this->sId;
}
$this->sLabel = $oDomNode->GetChildText('label');
$this->sRelevanceCondition = $oDomNode->GetChildText('relevance-condition');
$sBlockNodeClass = $this->GetFormBlockClass();
$oBlockNode = new $sBlockNodeClass('foo');
foreach ($oBlockNode->GetInputs() as $oInput) {
$sInputName = $oInput->GetName();
$this->aInputs[$sInputName] = $oInput;
$sInputValue = $oDomNode->GetChildText($sInputName);
if (utils::IsNotNullOrEmptyString($sInputValue)) {
$this->aInputValues[$sInputName] = $sInputValue;
}
}
foreach ($oBlockNode->GetOutputs() as $oOutput) {
$this->aOutputs[] = $oOutput->GetName();
}
}
public function GetFormBlockOptions(): array
{
return $this->aFormBlockOptionsForPHP;
}
public function GetInputValues(): array
{
return $this->aInputValues;
}
public function GetInputType(string $sInputName): string
{
return $this->aInputs[$sInputName]->GetDataType();
}
public function GetDynamicInputValues(): array
{
return $this->aDynamicInputValues;
}
public function GetOutputs(): array
{
return $this->aOutputs;
}
public function SetRootId(string $sId): void
{
$this->sId = $sId;
$this->sIdWithPath = $sId;
}
abstract public function IsLeaf(): bool;
abstract public function ToPHPFormBlock(array &$aPHPFragments = []): string;
/**
* @param array $aPHPFragments
*
* @return string
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
*/
protected function GetLocalPHPForValueType(?string $sFormBlockClass = null): string
{
$sFormBlockClass = $sFormBlockClass ?? $this->GetFormBlockClass();
$sInputs = '';
$sPrerequisiteExpressions = '';
if (!is_null($this->sRelevanceCondition)) {
$this->GenerateInputs('visible', $this->sRelevanceCondition, $sPrerequisiteExpressions, $sInputs);
}
foreach ($this->GetInputValues() as $sInputName => $sValue) {
$this->GenerateInputs($sInputName, $sValue, $sPrerequisiteExpressions, $sInputs);
}
foreach ($this->GetDynamicInputValues() as $sInputName => $sValue) {
$this->GenerateInputs($sInputName, $sValue, $sPrerequisiteExpressions, $sInputs, true);
}
$sLabel = utils::QuoteForPHP($this->sLabel ?? '');
$aOptions = [
'label' => $sLabel,
];
$aOptions += $this->GetFormBlockOptions();
$sOptions = '';
foreach ($aOptions as $sOption => $sValue) {
$sOptions .= "\t\t\t".utils::QuoteForPHP($sOption)." => $sValue,\n";
}
return <<<PHP
\t\t{$sPrerequisiteExpressions}\$this->Add('$this->sId', '$sFormBlockClass', [
$sOptions\t\t]){$sInputs};\n
PHP;
}
private function GenerateInputs(string $sInputName, string $sValue, string &$sPrerequisiteExpressions, string &$sInputs, bool $bIsDynamic = false): void
{
if (preg_match('/^{{(?<node>\w+)\.(?<output>\w+)}}$/', $sValue, $aMatches) === 1) {
$sVerb = $bIsDynamic ? 'AddInputDependsOn' : 'InputDependsOn';
$sInputs .= "\n ->$sVerb('$sInputName', '{$aMatches['node']}', '{$aMatches['output']}')";
} elseif (preg_match('/^{{(?<expression>.*)}}$/', $sValue, $aMatches) === 1) {
$sExpression = $aMatches['expression'];
$sBindings = '';
try {
$oExpression = Expression::FromOQL($sExpression);
} catch (Exception $e) {
throw new PropertyTypeException("Node: {$this->sId}, invalid syntax in condition: ".$e->getMessage());
}
$aFieldsToResolve = array_unique($oExpression->ListRequiredFields());
foreach ($aFieldsToResolve as $sFieldToResolve) {
if (preg_match('/(?<node>\w+)\.(?<output>\w+)/', $sFieldToResolve, $aMatches) === 1) {
$sNode = $aMatches['node'];
$oSibling = $this->GetSibling($sNode);
if (is_null($oSibling)) {
// Search in collection
if (is_a($this->oParent ?? null, 'Combodo-ValueType-Collection')) {
$bSourceNodeFound = false;
$aSiblings = $this->oParent->GetChildren();
foreach ($aSiblings as $oSibling) {
if ($oSibling->sId == $sNode) {
$bSourceNodeFound = true;
break;
}
}
if (!$bSourceNodeFound) {
throw new PropertyTypeException("node: {$this->sId}, source: $sNode not found in collection: {$this->oParent->sId}");
}
} else {
throw new PropertyTypeException("Node: {$this->sId}, invalid source in condition: $sNode");
}
}
$sOutput = $aMatches['output'];
if (!in_array($sOutput, $oSibling->GetOutputs())) {
throw new PropertyTypeException("Node: {$this->sId}, invalid output in condition: $sFieldToResolve");
}
$sBindings .= "\n\t\t\t->AddInputDependsOn('{$sNode}.$sOutput', '$sNode', '$sOutput')";
} else {
throw new PropertyTypeException("Node: {$this->sId}, missing output or source in condition: $sFieldToResolve");
}
}
$sExpressionClass = match ($this->GetInputType($sInputName)) {
BooleanIOFormat::class => BooleanExpressionFormBlock::class,
StringIOFormat::class, ClassIOFormat::class => StringExpressionFormBlock::class,
NumberIOFormat::class => NumberExpressionFormBlock::class,
default => throw new PropertyTypeException("Node: {$this->sId}, unsupported expression for input type: $sInputName"),
};
$sExpression = utils::QuoteForPHP($sExpression);
$sPrerequisiteExpressions = <<<PHP
\$this->Add('{$this->sId}_{$sInputName}_expression', '$sExpressionClass', [
'expression' => $sExpression,
]){$sBindings};\n\n\t\t
PHP;
$sVerb = $bIsDynamic ? 'AddInputDependsOn' : 'InputDependsOn';
$sInputs .= "\n\t\t\t->$sVerb('$sInputName', '{$this->sId}_{$sInputName}_expression', 'result')";
} else {
$sInputs .= "\n\t\t\t->SetInputValue('$sInputName', ".utils::QuoteForPHP($sValue).')';
}
}
protected function GetSibling(string $sId): ?AbstractValueType
{
if (is_null($this->oParent)) {
return null;
}
return $this->oParent->GetChild($sId);
}
}

View File

@@ -0,0 +1,63 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType\ValueType\Branch;
use Combodo\iTop\PropertyType\ValueType\AbstractValueType;
/**
* @since 3.3.0
*/
abstract class AbstractBranchValueType extends AbstractValueType
{
/** @var AbstractValueType[] */
protected array $aChildren = [];
/**
* @return bool
*/
public function IsLeaf(): bool
{
return false;
}
/**
* @return bool
*/
public function IsRoot(): bool
{
return is_null($this->oParent);
}
/**
* @param \Combodo\iTop\PropertyType\ValueType\AbstractValueType $oChild
*
* @return void
*/
public function AddChild(AbstractValueType $oChild): void
{
$this->aChildren[$oChild->sId] = $oChild;
}
/**
* @param string $sId
*
* @return \Combodo\iTop\PropertyType\ValueType\AbstractValueType|null
*/
public function GetChild(string $sId): ?AbstractValueType
{
return $this->aChildren[$sId] ?? null;
}
/**
* @return AbstractValueType[]
*/
public function GetChildren(): array
{
return $this->aChildren;
}
}

View File

@@ -0,0 +1,77 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType\ValueType\Branch;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\Base\CollectionBlock;
use Combodo\iTop\PropertyType\ValueType\AbstractValueType;
use Combodo\iTop\PropertyType\ValueType\ValueTypeFactory;
use utils;
/**
* @since 3.3.0
*/
class ValueTypeCollection extends ValueTypePropertyTree
{
/**
* @param \Combodo\iTop\DesignElement $oDomNode
* @param \Combodo\iTop\PropertyType\ValueType\Branch\AbstractBranchValueType|null $oParent
*
* @return void
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException
*/
public function InitFromDomNode(DesignElement $oDomNode, ?AbstractBranchValueType $oParent = null): void
{
parent::InitFromDomNode($oDomNode, $oParent);
$this->aFormBlockOptionsForPHP['button_label'] = utils::QuoteForPHP('UI:AddSubTree');
$this->sSubTreeClass = 'SubFormFor__'.$this->sIdWithPath;
$this->aFormBlockOptionsForPHP['block_entry_type'] = utils::QuoteForPHP($this->sSubTreeClass);
// read child properties
foreach ($oDomNode->GetUniqueElement('prototype')->childNodes as $oNode) {
if ($oNode instanceof DesignElement) {
$this->AddChild(ValueTypeFactory::GetInstance()->CreateValueTypeFromDomNode($oNode, $this));
}
}
}
public function GetFormBlockClass(): string
{
return CollectionBlock::class;
}
/**
* @param array $aPHPFragments
*
* @return string
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
*/
public function ToPHPFormBlock(array &$aPHPFragments = []): string
{
$sSubClassPHP = <<<PHP
class $this->sSubTreeClass extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
PHP;
foreach ($this->GetChildren() as $oProperty) {
$sSubClassPHP .= "\n".$oProperty->ToPHPFormBlock($aPHPFragments);
}
$sSubClassPHP .= <<<PHP
}
}
PHP;
$aPHPFragments[] = $sSubClassPHP;
return $this->GetLocalPHPForValueType();
}
}

View File

@@ -0,0 +1,89 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType\ValueType\Branch;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\Base\FormBlock;
use Combodo\iTop\Forms\Block\Expression\BooleanExpressionFormBlock;
use Combodo\iTop\Forms\Block\Expression\NumberExpressionFormBlock;
use Combodo\iTop\Forms\Block\Expression\StringExpressionFormBlock;
use Combodo\iTop\Forms\IO\Format\BooleanIOFormat;
use Combodo\iTop\Forms\IO\Format\ClassIOFormat;
use Combodo\iTop\Forms\IO\Format\NumberIOFormat;
use Combodo\iTop\Forms\IO\Format\StringIOFormat;
use Combodo\iTop\PropertyType\PropertyTypeException;
use Combodo\iTop\PropertyType\ValueType\AbstractValueType;
use Combodo\iTop\PropertyType\ValueType\ValueTypeFactory;
use Exception;
use Expression;
use utils;
/**
* @since 3.3.0
*/
class ValueTypePropertyTree extends AbstractBranchValueType
{
protected string $sSubTreeClass;
public function GetFormBlockClass(): string
{
return FormBlock::class;
}
/**
* @param \Combodo\iTop\DesignElement $oDomNode
* @param \Combodo\iTop\PropertyType\ValueType\Branch\AbstractBranchValueType|null $oParent
*
* @return void
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException
*/
public function InitFromDomNode(DesignElement $oDomNode, ?AbstractBranchValueType $oParent = null): void
{
parent::InitFromDomNode($oDomNode, $oParent);
// read child properties
$oNodes = $oDomNode->GetOptionalElement('nodes');
if (!is_null($oNodes)) {
foreach ($oNodes->childNodes as $oNode) {
if ($oNode instanceof DesignElement) {
$this->AddChild(ValueTypeFactory::GetInstance()->CreateValueTypeFromDomNode($oNode, $this));
}
}
}
}
public function ToPHPFormBlock(array &$aPHPFragments = []): string
{
if ($this->IsRoot()) {
$this->sSubTreeClass = 'FormFor__'.$this->sId;
} else {
$this->sSubTreeClass = 'SubFormFor__'.$this->sIdWithPath;
}
$sLocalPHP = <<<PHP
class $this->sSubTreeClass extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
PHP;
foreach ($this->aChildren as $oChild) {
$sLocalPHP .= "\n".$oChild->ToPHPFormBlock($aPHPFragments);
}
$sLocalPHP .= <<<PHP
}
}
PHP;
$aPHPFragments[] = $sLocalPHP;
return $this->GetLocalPHPForValueType($this->sSubTreeClass);
}
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\Expression\BooleanExpressionFormBlock;
use Combodo\iTop\Forms\Block\Expression\NumberExpressionFormBlock;
use Combodo\iTop\Forms\Block\Expression\StringExpressionFormBlock;
use Combodo\iTop\Forms\IO\Format\BooleanIOFormat;
use Combodo\iTop\Forms\IO\Format\ClassIOFormat;
use Combodo\iTop\Forms\IO\Format\NumberIOFormat;
use Combodo\iTop\Forms\IO\Format\StringIOFormat;
use Combodo\iTop\PropertyType\PropertyTypeException;
use Combodo\iTop\PropertyType\ValueType\AbstractValueType;
use Exception;
use Expression;
use utils;
/**
* @since 3.3.0
*/
abstract class AbstractLeafValueType extends AbstractValueType
{
public function IsLeaf(): bool
{
return true;
}
/**
* @param array $aPHPFragments
*
* @return string
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
*/
public function ToPHPFormBlock(array &$aPHPFragments = []): string
{
return $this->GetLocalPHPForValueType();
}
}

View File

@@ -1,18 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\DataModel\Dashlet\AggregateFunctionFormBlock; use Combodo\iTop\Forms\Block\DataModel\Dashlet\AggregateFunctionFormBlock;
/** /**
* @since 3.3.0 * @since 3.3.0
*/ */
class ValueTypeAggregateFunction extends AbstractValueType class ValueTypeAggregateFunction extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -1,16 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\Base\CheckboxFormBlock; use Combodo\iTop\Forms\Block\Base\CheckboxFormBlock;
use Combodo\iTop\PropertyTree\ValueType\AbstractValueType;
class ValueTypeBoolean extends AbstractValueType /**
* @since 3.3.0
*/
class ValueTypeBoolean extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -1,28 +1,29 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\DesignElement; use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\Base\ChoiceFormBlock; use Combodo\iTop\Forms\Block\Base\ChoiceFormBlock;
use Combodo\iTop\PropertyTree\AbstractProperty; use Combodo\iTop\PropertyType\ValueType\Branch\AbstractBranchValueType;
use Combodo\iTop\PropertyType\ValueType\Branch\ValueTypePropertyTree;
use utils; use utils;
/** /**
* @since 3.3.0 * @since 3.3.0
*/ */
class ValueTypeChoice extends AbstractValueType class ValueTypeChoice extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {
return ChoiceFormBlock::class; return ChoiceFormBlock::class;
} }
public function InitFromDomNode(DesignElement $oDomNode, AbstractProperty $oParent): void public function InitFromDomNode(DesignElement $oDomNode, ?AbstractBranchValueType $oParent = null): void
{ {
parent::InitFromDomNode($oDomNode, $oParent); parent::InitFromDomNode($oDomNode, $oParent);

View File

@@ -1,26 +1,29 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\DesignElement; use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\Base\ChoiceFromInputsBlock; use Combodo\iTop\Forms\Block\Base\ChoiceFromInputsBlock;
use Combodo\iTop\PropertyTree\AbstractProperty; use Combodo\iTop\PropertyType\ValueType\Branch\AbstractBranchValueType;
use Combodo\iTop\PropertyTree\ValueType\AbstractValueType; use Combodo\iTop\PropertyType\ValueType\Branch\ValueTypePropertyTree;
use utils; use utils;
class ValueTypeChoiceFromInput extends AbstractValueType /**
* @since 3.3.0
*/
class ValueTypeChoiceFromInput extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {
return ChoiceFromInputsBlock::class; return ChoiceFromInputsBlock::class;
} }
public function InitFromDomNode(DesignElement $oDomNode, AbstractProperty $oParent): void public function InitFromDomNode(DesignElement $oDomNode, ?AbstractBranchValueType $oParent = null): void
{ {
parent::InitFromDomNode($oDomNode, $oParent); parent::InitFromDomNode($oDomNode, $oParent);

View File

@@ -1,21 +1,23 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\DesignElement; use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\Base\ChoiceFormBlock; use Combodo\iTop\Forms\Block\Base\ChoiceFormBlock;
use Combodo\iTop\Forms\Block\Base\TextFormBlock; use Combodo\iTop\PropertyType\ValueType\Branch\AbstractBranchValueType;
use Combodo\iTop\PropertyTree\AbstractProperty; use Combodo\iTop\PropertyType\ValueType\Branch\ValueTypePropertyTree;
use Combodo\iTop\PropertyTree\ValueType\AbstractValueType;
use Combodo\iTop\Service\DependencyInjection\ServiceLocator; use Combodo\iTop\Service\DependencyInjection\ServiceLocator;
use utils; use utils;
class ValueTypeClass extends AbstractValueType /**
* @since 3.3.0
*/
class ValueTypeClass extends AbstractLeafValueType
{ {
protected array $aCategories = []; protected array $aCategories = [];
@@ -24,7 +26,7 @@ class ValueTypeClass extends AbstractValueType
return ChoiceFormBlock::class; return ChoiceFormBlock::class;
} }
public function InitFromDomNode(DesignElement $oDomNode, AbstractProperty $oParent): void public function InitFromDomNode(DesignElement $oDomNode, ?AbstractBranchValueType $oParent = null): void
{ {
parent::InitFromDomNode($oDomNode, $oParent); parent::InitFromDomNode($oDomNode, $oParent);

View File

@@ -1,20 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\DataModel\AttributeChoiceFormBlock; use Combodo\iTop\Forms\Block\DataModel\AttributeChoiceFormBlock;
use utils;
/** /**
* @since 3.3.0 * @since 3.3.0
*/ */
class ValueTypeClassAttribute extends AbstractValueType class ValueTypeClassAttribute extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -1,18 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\DataModel\Dashlet\ClassAttributeGroupByFormBlock; use Combodo\iTop\Forms\Block\DataModel\Dashlet\ClassAttributeGroupByFormBlock;
/** /**
* @since 3.3.0 * @since 3.3.0
*/ */
class ValueTypeClassAttributeGroupBy extends AbstractValueType class ValueTypeClassAttributeGroupBy extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -1,18 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\DataModel\AttributeValueChoiceFormBlock; use Combodo\iTop\Forms\Block\DataModel\AttributeValueChoiceFormBlock;
/** /**
* @since 3.3.0 * @since 3.3.0
*/ */
class ValueTypeClassAttributeValue extends AbstractValueType class ValueTypeClassAttributeValue extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -0,0 +1,38 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\Base\ChoiceFormBlock;
use Combodo\iTop\Forms\Block\Base\FormBlock;
use Combodo\iTop\PropertyType\ValueType\Branch\AbstractBranchValueType;
use Combodo\iTop\PropertyType\ValueType\Leaf\AbstractLeafValueType;
use Combodo\iTop\PropertyType\ValueType\ValueTypeFactory;
class ValueTypeCollectionOfValues extends AbstractLeafValueType
{
private string $sFormBlockClass;
public function GetFormBlockClass(): string
{
return $this->sFormBlockClass;
}
public function InitFromDomNode(DesignElement $oDomNode, ?AbstractBranchValueType $oParent = null): void
{
$oNode = $oDomNode->GetUniqueElement('value-type');
$oRealValueType = ValueTypeFactory::GetInstance()->CreateValueTypeFromDomNode($oNode, $oParent);
$this->sFormBlockClass = $oRealValueType->getFormBlockClass();
if (is_a($this->sFormBlockClass, ChoiceFormBlock::class, true)) {
$this->aFormBlockOptionsForPHP['multiple'] = 'true';
}
parent::InitFromDomNode($oDomNode, $oParent);
}
}

View File

@@ -1,15 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\Base\ChoiceFormBlock; use Combodo\iTop\Forms\Block\Base\ChoiceFormBlock;
class ValueTypeIcon extends AbstractValueType /**
* @since 3.3.0
*/
class ValueTypeIcon extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -1,18 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\Base\IntegerFormBlock; use Combodo\iTop\Forms\Block\Base\IntegerFormBlock;
/** /**
* @since 3.3.0 * @since 3.3.0
*/ */
class ValueTypeInteger extends AbstractValueType class ValueTypeInteger extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -1,18 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\DataModel\LabelFormBlock; use Combodo\iTop\Forms\Block\DataModel\LabelFormBlock;
/** /**
* @since 3.3.0 * @since 3.3.0
*/ */
class ValueTypeLabel extends AbstractValueType class ValueTypeLabel extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -1,18 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\DataModel\OqlFormBlock; use Combodo\iTop\Forms\Block\DataModel\OqlFormBlock;
/** /**
* @since 3.3.0 * @since 3.3.0
*/ */
class ValueTypeOQL extends AbstractValueType class ValueTypeOQL extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -1,16 +1,16 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
/** /**
* @since 3.3.0 * @since 3.3.0
*/ */
class ValueTypeProfileName extends AbstractValueType class ValueTypeProfileName extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -1,15 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\Base\TextFormBlock; use Combodo\iTop\Forms\Block\Base\TextFormBlock;
class ValueTypeString extends AbstractValueType /**
* @since 3.3.0
*/
class ValueTypeString extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -1,15 +1,18 @@
<?php <?php
/* /*
* @copyright Copyright (C) 2010-2025 Combodo SAS * @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType\Leaf;
use Combodo\iTop\Forms\Block\Base\TextAreaFormBlock; use Combodo\iTop\Forms\Block\Base\TextAreaFormBlock;
class ValueTypeText extends AbstractValueType /**
* @since 3.3.0
*/
class ValueTypeText extends AbstractLeafValueType
{ {
public function GetFormBlockClass(): string public function GetFormBlockClass(): string
{ {

View File

@@ -5,13 +5,16 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
namespace Combodo\iTop\PropertyTree\ValueType; namespace Combodo\iTop\PropertyType\ValueType;
use Combodo\iTop\DesignElement; use Combodo\iTop\DesignElement;
use Combodo\iTop\PropertyTree\AbstractProperty; use Combodo\iTop\PropertyType\PropertyTypeException;
use Combodo\iTop\PropertyTree\PropertyTreeException; use utils;
use DOMElement;
/**
* Build Value type from XML DOM
* @since 3.3.0
*/
class ValueTypeFactory class ValueTypeFactory
{ {
private static ValueTypeFactory $oInstance; private static ValueTypeFactory $oInstance;
@@ -31,16 +34,21 @@ class ValueTypeFactory
/** /**
* @param \Combodo\iTop\DesignElement $oDomNode * @param \Combodo\iTop\DesignElement $oDomNode
* @param \Combodo\iTop\PropertyTree\AbstractProperty $oParent * @param \Combodo\iTop\PropertyType\ValueType\AbstractValueType|null $oParent
* *
* @return \Combodo\iTop\PropertyTree\ValueType\AbstractValueType * @return \Combodo\iTop\PropertyType\ValueType\AbstractValueType
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException * @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException * @throws \DOMFormatException
*/ */
public function CreateValueTypeFromDomNode(DesignElement $oDomNode, AbstractProperty $oParent): AbstractValueType public function CreateValueTypeFromDomNode(DesignElement $oDomNode, ?AbstractValueType $oParent = null): AbstractValueType
{ {
$sNodeType = $oDomNode->getAttribute('xsi:type'); $sNodeType = $oDomNode->getAttribute('xsi:type');
if (utils::IsNullOrEmptyString($sNodeType)) {
$sId = $oDomNode->getAttribute('id');
throw new PropertyTypeException("Node: $sId, missing value-type in node specification");
}
if (is_a($sNodeType, AbstractValueType::class, true)) { if (is_a($sNodeType, AbstractValueType::class, true)) {
$oNode = new $sNodeType(); $oNode = new $sNodeType();
$oNode->InitFromDomNode($oDomNode, $oParent); $oNode->InitFromDomNode($oDomNode, $oParent);
@@ -48,6 +56,7 @@ class ValueTypeFactory
return $oNode; return $oNode;
} }
throw new PropertyTreeException('Unknown value-type node class: '.json_encode($sNodeType)); $sId = $oDomNode->getAttribute('id');
throw new PropertyTypeException("Node: $sId, unknown type node class: ".json_encode($sNodeType));
} }
} }

View File

@@ -97,21 +97,23 @@ class_alias(\Combodo\iTop\Core\AttributeDefinition\AttributeURL::class, 'Attribu
class_alias(\Combodo\iTop\Core\AttributeDefinition\iAttributeNoGroupBy::class, 'iAttributeNoGroupBy'); class_alias(\Combodo\iTop\Core\AttributeDefinition\iAttributeNoGroupBy::class, 'iAttributeNoGroupBy');
class_alias(\Combodo\iTop\Core\AttributeDefinition\MissingColumnException::class, 'MissingColumnException'); class_alias(\Combodo\iTop\Core\AttributeDefinition\MissingColumnException::class, 'MissingColumnException');
class_alias(\Combodo\iTop\PropertyTree\PropertyTree::class, 'Combodo-PropertyTree'); class_alias(\Combodo\iTop\PropertyType\PropertyType::class, 'Combodo-PropertyType');
class_alias(\Combodo\iTop\PropertyTree\Property::class, 'Combodo-Property');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeAggregateFunction::class, 'Combodo-ValueType-AggregateFunction'); class_alias(\Combodo\iTop\PropertyType\ValueType\Branch\ValueTypeCollection::class, 'Combodo-ValueType-Collection');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeBoolean::class, 'Combodo-ValueType-Boolean'); class_alias(\Combodo\iTop\PropertyType\ValueType\Branch\ValueTypePropertyTree::class, 'Combodo-ValueType-PropertyTree');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeChoice::class, 'Combodo-ValueType-Choice');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeChoiceFromInput::class, 'Combodo-ValueType-ChoiceFromInput'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeAggregateFunction::class, 'Combodo-ValueType-AggregateFunction');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClass::class, 'Combodo-ValueType-Class'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeBoolean::class, 'Combodo-ValueType-Boolean');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClassAttribute::class, 'Combodo-ValueType-ClassAttribute'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeChoice::class, 'Combodo-ValueType-Choice');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClassAttributeGroupBy::class, 'Combodo-ValueType-ClassAttributeGroupBy'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeChoiceFromInput::class, 'Combodo-ValueType-ChoiceFromInput');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClassAttributeValue::class, 'Combodo-ValueType-ClassAttributeValue'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeClass::class, 'Combodo-ValueType-Class');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeCollection::class, 'Combodo-ValueType-Collection'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeClassAttribute::class, 'Combodo-ValueType-ClassAttribute');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeIcon::class, 'Combodo-ValueType-Icon'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeClassAttributeGroupBy::class, 'Combodo-ValueType-ClassAttributeGroupBy');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeInteger::class, 'Combodo-ValueType-Integer'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeClassAttributeValue::class, 'Combodo-ValueType-ClassAttributeValue');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeLabel::class, 'Combodo-ValueType-Label'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeCollectionOfValues::class, 'Combodo-ValueType-CollectionOfValues');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeOQL::class, 'Combodo-ValueType-OQL'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeIcon::class, 'Combodo-ValueType-Icon');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeString::class, 'Combodo-ValueType-String'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeInteger::class, 'Combodo-ValueType-Integer');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeText::class, 'Combodo-ValueType-Text'); class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeLabel::class, 'Combodo-ValueType-Label');
class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeOQL::class, 'Combodo-ValueType-OQL');
class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeString::class, 'Combodo-ValueType-String');
class_alias(\Combodo\iTop\PropertyType\ValueType\Leaf\ValueTypeText::class, 'Combodo-ValueType-Text');

View File

@@ -182,7 +182,6 @@ class FormBindingTest extends AbstractFormsTest
'Attribute -> Boolean' => [AttributeIOFormat::class, BooleanIOFormat::class], 'Attribute -> Boolean' => [AttributeIOFormat::class, BooleanIOFormat::class],
'Attribute -> Class' => [AttributeIOFormat::class, ClassIOFormat::class], 'Attribute -> Class' => [AttributeIOFormat::class, ClassIOFormat::class],
'Attribute -> Number' => [AttributeIOFormat::class, NumberIOFormat::class], 'Attribute -> Number' => [AttributeIOFormat::class, NumberIOFormat::class],
'Attribute -> String' => [AttributeIOFormat::class, StringIOFormat::class],
'Boolean => Attribute' => [BooleanIOFormat::class, AttributeIOFormat::class], 'Boolean => Attribute' => [BooleanIOFormat::class, AttributeIOFormat::class],
'Boolean => Class' => [BooleanIOFormat::class, ClassIOFormat::class], 'Boolean => Class' => [BooleanIOFormat::class, ClassIOFormat::class],
@@ -192,7 +191,6 @@ class FormBindingTest extends AbstractFormsTest
'Class => Attribute' => [ClassIOFormat::class, AttributeIOFormat::class], 'Class => Attribute' => [ClassIOFormat::class, AttributeIOFormat::class],
'Class => Boolean' => [ClassIOFormat::class, BooleanIOFormat::class], 'Class => Boolean' => [ClassIOFormat::class, BooleanIOFormat::class],
'Class => Number' => [ClassIOFormat::class, NumberIOFormat::class], 'Class => Number' => [ClassIOFormat::class, NumberIOFormat::class],
'Class -> String' => [ClassIOFormat::class, StringIOFormat::class],
'Number => Attribute' => [NumberIOFormat::class, AttributeIOFormat::class], 'Number => Attribute' => [NumberIOFormat::class, AttributeIOFormat::class],
'Number => Class' => [NumberIOFormat::class, ClassIOFormat::class], 'Number => Class' => [NumberIOFormat::class, ClassIOFormat::class],
@@ -227,8 +225,10 @@ class FormBindingTest extends AbstractFormsTest
{ {
return [ return [
'Attribute -> Attribute' => [AttributeIOFormat::class, AttributeIOFormat::class], 'Attribute -> Attribute' => [AttributeIOFormat::class, AttributeIOFormat::class],
'Attribute -> String' => [AttributeIOFormat::class, StringIOFormat::class],
'Boolean => Boolean' => [BooleanIOFormat::class, BooleanIOFormat::class], 'Boolean => Boolean' => [BooleanIOFormat::class, BooleanIOFormat::class],
'Class => Class' => [ClassIOFormat::class, ClassIOFormat::class], 'Class => Class' => [ClassIOFormat::class, ClassIOFormat::class],
'Class -> String' => [ClassIOFormat::class, StringIOFormat::class],
'Number => Number' => [NumberIOFormat::class, NumberIOFormat::class], 'Number => Number' => [NumberIOFormat::class, NumberIOFormat::class],
'String => String' => [StringIOFormat::class, StringIOFormat::class], 'String => String' => [StringIOFormat::class, StringIOFormat::class],
]; ];

View File

@@ -5,7 +5,7 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
use Combodo\iTop\Forms\Compiler\FormsCompiler; use Combodo\iTop\PropertyType\Compiler\PropertyTypeCompiler;
use Combodo\iTop\Service\DependencyInjection\ServiceLocator; use Combodo\iTop\Service\DependencyInjection\ServiceLocator;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
@@ -18,15 +18,15 @@ class FormsCompilerTest extends ItopDataTestCase
* @param string $sExpectedPHP * @param string $sExpectedPHP
* *
* @return void * @return void
* @throws \Combodo\iTop\Forms\Compiler\FormsCompilerException * @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException * @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException * @throws \DOMFormatException
*/ */
public function testCompileFormFromXML(string $sXMLContent, string $sExpectedPHP) public function testCompileFormFromXML(string $sXMLContent, string $sExpectedPHP)
{ {
ServiceLocator::GetInstance()->RegisterService('ModelReflection', new ModelReflectionRuntime()); ServiceLocator::GetInstance()->RegisterService('ModelReflection', new ModelReflectionRuntime());
$sProducedPHP = FormsCompiler::GetInstance()->CompileFormFromXML($sXMLContent); $sProducedPHP = PropertyTypeCompiler::GetInstance()->CompileFormFromXML($sXMLContent);
$this->AssertPHPCodeIsValid($sProducedPHP); $this->AssertPHPCodeIsValid($sProducedPHP);
$sMessage = $this->dataName(); $sMessage = $this->dataName();
@@ -39,21 +39,20 @@ class FormsCompilerTest extends ItopDataTestCase
'Basic scalar properties should generate PHP' => [ 'Basic scalar properties should generate PHP' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<property_tree id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="title_property"> <node id="title_property" xsi:type="Combodo-ValueType-Label">
<label>UI:BasicTest:Prop-Title</label> <label>UI:BasicTest:Prop-Title</label>
<value-type xsi:type="Combodo-ValueType-Label">
</value-type>
</node> </node>
<node id="class_property"> <node id="class_property" xsi:type="Combodo-ValueType-Class">
<label>UI:BasicTest:Prop-Class</label> <label>UI:BasicTest:Prop-Class</label>
<value-type xsi:type="Combodo-ValueType-Class">
<categories-csv>test</categories-csv> <categories-csv>test</categories-csv>
</value-type>
</node> </node>
</nodes> </nodes>
</property_tree> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__basic_test extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__basic_test extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -77,10 +76,13 @@ PHP,
'Empty property tree should generate minimal PHP' => [ 'Empty property tree should generate minimal PHP' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<property_tree id="EmptyTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="EmptyTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
</nodes> </nodes>
</property_tree> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__EmptyTest extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__EmptyTest extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -94,10 +96,13 @@ PHP,
'Empty property tree lower case should generate lower case class name' => [ 'Empty property tree lower case should generate lower case class name' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<property_tree id="empty_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="empty_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
</nodes> </nodes>
</property_tree> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__empty_test extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__empty_test extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -111,16 +116,15 @@ PHP,
'Properties with all value-types' => [ 'Properties with all value-types' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<property_tree id="AllValueTypesTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="AllValueTypesTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="aggregate_function_property"> <node id="aggregate_function_property" xsi:type="Combodo-ValueType-AggregateFunction">
<label>UI:AggregateFunction</label> <label>UI:AggregateFunction</label>
<value-type xsi:type="Combodo-ValueType-AggregateFunction">
</value-type>
</node> </node>
<node id="choice_property"> <node id="choice_property" xsi:type="Combodo-ValueType-Choice">
<label>UI:Choice</label> <label>UI:Choice</label>
<value-type xsi:type="Combodo-ValueType-Choice">
<values> <values>
<value id="value_a"> <value id="value_a">
<label>Label A</label> <label>Label A</label>
@@ -129,52 +133,34 @@ PHP,
<label>Label B</label> <label>Label B</label>
</value> </value>
</values> </values>
</value-type>
</node> </node>
<node id="class_property"> <node id="class_property" xsi:type="Combodo-ValueType-Class">
<label>UI:Class</label> <label>UI:Class</label>
<value-type xsi:type="Combodo-ValueType-Class">
<categories-csv>test</categories-csv> <categories-csv>test</categories-csv>
</value-type>
</node> </node>
<node id="class_attribute_property"> <node id="class_attribute_property" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:ClassAttribute</label> <label>UI:ClassAttribute</label>
<value-type xsi:type="Combodo-ValueType-ClassAttribute">
</value-type>
</node> </node>
<node id="class_attribute_group_by_property"> <node id="class_attribute_group_by_property" xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
<label>UI:ClassAttributeGroupBy</label> <label>UI:ClassAttributeGroupBy</label>
<value-type xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
</value-type>
</node> </node>
<node id="class_attribute_value_property"> <node id="class_attribute_value_property" xsi:type="Combodo-ValueType-ClassAttributeValue">
<label>UI:ClassAttributeValue</label> <label>UI:ClassAttributeValue</label>
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
</value-type>
</node> </node>
<node id="integer_property"> <node id="integer_property" xsi:type="Combodo-ValueType-Integer">
<label>UI:Integer</label> <label>UI:Integer</label>
<value-type xsi:type="Combodo-ValueType-Integer">
</value-type>
</node> </node>
<node id="label_property"> <node id="label_property" xsi:type="Combodo-ValueType-Label">
<label>UI:Label</label> <label>UI:Label</label>
<value-type xsi:type="Combodo-ValueType-Label">
</value-type>
</node> </node>
<node id="oql_property"> <node id="oql_property" xsi:type="Combodo-ValueType-OQL">
<label>UI:OQL</label> <label>UI:OQL</label>
<value-type xsi:type="Combodo-ValueType-OQL">
</value-type>
</node> </node>
<node id="string_property"> <node id="string_property" xsi:type="Combodo-ValueType-String">
<label>UI:String</label> <label>UI:String</label>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
<node id="choice_from_input"> <node id="choice_from_input" xsi:type="Combodo-ValueType-ChoiceFromInput">
<label>UI:ChoiceFromInput</label> <label>UI:ChoiceFromInput</label>
<value-type xsi:type="Combodo-ValueType-ChoiceFromInput">
<values> <values>
<value id="value_a"> <value id="value_a">
<label>{{class_attribute_property.label}}</label> <label>{{class_attribute_property.label}}</label>
@@ -183,10 +169,10 @@ PHP,
<label>{{class_attribute_group_by_property.label}}</label> <label>{{class_attribute_group_by_property.label}}</label>
</value> </value>
</values> </values>
</value-type>
</node> </node>
</nodes> </nodes>
</property_tree> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__AllValueTypesTest extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__AllValueTypesTest extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -252,28 +238,25 @@ PHP,
'Collection of trees' => [ 'Collection of trees' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<property_tree id="collection_of_trees_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="collection_of_trees_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="sub_tree_collection"> <node id="sub_tree_collection" xsi:type="Combodo-ValueType-Collection">
<label>UI:SubTree</label> <label>UI:SubTree</label>
<value-type xsi:type="Combodo-ValueType-Collection">
<prototype> <prototype>
<node id="string_property"> <node id="string_property" xsi:type="Combodo-ValueType-String">
<label>UI:String</label> <label>UI:String</label>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
<node id="integer_property"> <node id="integer_property" xsi:type="Combodo-ValueType-Integer">
<label>UI:Integer</label> <label>UI:Integer</label>
<relevance-condition>{{string_property.text != 'no-display'}}</relevance-condition> <relevance-condition>{{string_property.text != 'no-display'}}</relevance-condition>
<value-type xsi:type="Combodo-ValueType-Integer">
</value-type>
</node> </node>
</prototype> </prototype>
</value-type>
</node> </node>
</nodes> </nodes>
</property_tree> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class SubFormFor__collection_of_trees_test__sub_tree_collection extends Combodo\iTop\Forms\Block\Base\FormBlock class SubFormFor__collection_of_trees_test__sub_tree_collection extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -313,17 +296,18 @@ PHP,
'Static inputs should be bound and invalid input should be ignored' => [ 'Static inputs should be bound and invalid input should be ignored' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="input_static_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="input_static_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="class_attribute_property"> <node id="class_attribute_property" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:ClassAttribute</label> <label>UI:ClassAttribute</label>
<value-type xsi:type="Combodo-ValueType-ClassAttribute">
<class>Contact</class> <class>Contact</class>
<invalid-input>Test</invalid-input> <invalid-input>Test</invalid-input>
</value-type>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__input_static_test extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__input_static_test extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -342,17 +326,18 @@ PHP,
'Quotes should be handled gracefully' => [ 'Quotes should be handled gracefully' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="input_quotes_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="input_quotes_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="class_attribute_property"> <node id="class_attribute_property" xsi:type="Combodo-ValueType-ClassAttribute">
<label>'Class' and "Attribute"</label> <label>'Class' and "Attribute"</label>
<value-type xsi:type="Combodo-ValueType-ClassAttribute">
<class>{{CONCAT("'", '"')}}</class> <class>{{CONCAT("'", '"')}}</class>
<category>'Class' and "Attribute"</category> <category>'Class' and "Attribute"</category>
</value-type>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__input_quotes_test extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__input_quotes_test extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -376,22 +361,21 @@ PHP,
'Dynamic input should be bound' => [ 'Dynamic input should be bound' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="input_binding_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="input_binding_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="class_property"> <node id="class_property" xsi:type="Combodo-ValueType-Class">
<label>UI:Class</label> <label>UI:Class</label>
<value-type xsi:type="Combodo-ValueType-Class">
<categories-csv>test</categories-csv> <categories-csv>test</categories-csv>
</value-type>
</node> </node>
<node id="class_attribute_property"> <node id="class_attribute_property" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:ClassAttribute</label> <label>UI:ClassAttribute</label>
<value-type xsi:type="Combodo-ValueType-ClassAttribute">
<class>{{class_property.text}}</class> <class>{{class_property.text}}</class>
</value-type>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__input_binding_test extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__input_binding_test extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -416,22 +400,21 @@ PHP,
'Dynamic input can be an expression' => [ 'Dynamic input can be an expression' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="input_binding_expression" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="input_binding_expression" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="class_property"> <node id="class_property" xsi:type="Combodo-ValueType-Class">
<label>UI:Class</label> <label>UI:Class</label>
<value-type xsi:type="Combodo-ValueType-Class">
<categories-csv>test</categories-csv> <categories-csv>test</categories-csv>
</value-type>
</node> </node>
<node id="class_attribute_property"> <node id="class_attribute_property" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:ClassAttribute</label> <label>UI:ClassAttribute</label>
<value-type xsi:type="Combodo-ValueType-ClassAttribute">
<class>{{IF(class_property.value = '', 'Person', class_property.value)}}</class> <class>{{IF(class_property.value = '', 'Person', class_property.value)}}</class>
</value-type>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__input_binding_expression extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__input_binding_expression extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -461,21 +444,20 @@ PHP,
'Relevance condition should generate a boolean block expression' => [ 'Relevance condition should generate a boolean block expression' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="source_property"> <node id="source_property" xsi:type="Combodo-ValueType-String">
<label>UI:Source</label> <label>UI:Source</label>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
<node id="dependant_property"> <node id="dependant_property" xsi:type="Combodo-ValueType-String">
<label>UI:Dependant</label> <label>UI:Dependant</label>
<relevance-condition>{{source_property.text != 'count'}}</relevance-condition> <relevance-condition>{{source_property.text != 'count'}}</relevance-condition>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__RelevanceCondition extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__RelevanceCondition extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -503,26 +485,23 @@ PHP,
'Complex Relevance condition should generate a boolean block expression' => [ 'Complex Relevance condition should generate a boolean block expression' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="ComplexRelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="ComplexRelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="source_a_property"> <node id="source_a_property" xsi:type="Combodo-ValueType-String">
<label>UI:Source</label> <label>UI:Source</label>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
<node id="source_b_property"> <node id="source_b_property" xsi:type="Combodo-ValueType-String">
<label>UI:Source</label> <label>UI:Source</label>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
<node id="dependant_property"> <node id="dependant_property" xsi:type="Combodo-ValueType-String">
<label>UI:Dependant</label> <label>UI:Dependant</label>
<relevance-condition>{{IF(source_a_property.text != '', source_a_property.text, source_b_property.text)}}</relevance-condition> <relevance-condition>{{IF(source_a_property.text != '', source_a_property.text, source_b_property.text)}}</relevance-condition>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__ComplexRelevanceCondition extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__ComplexRelevanceCondition extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -551,60 +530,73 @@ class FormFor__ComplexRelevanceCondition extends Combodo\iTop\Forms\Block\Base\F
} }
PHP, PHP,
], ],
'Class category for value type class' => [ 'Sub form generate a sub-form' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="ClassCategory" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_typeproperty_type id="SubFormTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="class_property"> <node id="sub_form_property" xsi:type="Combodo-ValueType-PropertyTree">
<label>UI:Class</label> <label>UI:SubForm:Title</label>
<value-type xsi:type="Combodo-ValueType-Class"> <nodes>
<categories-csv>addon/authentication,grant_by_profile,silo</categories-csv> <node id="string_property" xsi:type="Combodo-ValueType-String">
</value-type> <label>UI:String</label>
</node> </node>
</nodes> </nodes>
</node> </node>
</nodes>
</definition>
</property_typeproperty_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__ClassCategory extends Combodo\iTop\Forms\Block\Base\FormBlock class SubFormFor__SubFormTest__sub_form_property extends Combodo\iTop\Forms\Block\Base\FormBlock
{ {
protected function BuildForm(): void protected function BuildForm(): void
{ {
\$this->Add('class_property', 'Combodo\iTop\Forms\Block\Base\ChoiceFormBlock', [ \$this->Add('string_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
'label' => 'UI:Class', 'label' => 'UI:String',
'choices' => [ ]);
\Dict::S('Class:ActionEmail') => 'ActionEmail', }
\Dict::S('Class:ActionNewsroom') => 'ActionNewsroom', }
\Dict::S('Class:AuditCategory') => 'AuditCategory',
\Dict::S('Class:AuditDomain') => 'AuditDomain', class FormFor__SubFormTest extends Combodo\iTop\Forms\Block\Base\FormBlock
\Dict::S('Class:AuditRule') => 'AuditRule', {
\Dict::S('Class:OAuthClientAzure') => 'OAuthClientAzure', protected function BuildForm(): void
\Dict::S('Class:OAuthClientGoogle') => 'OAuthClientGoogle', {
\Dict::S('Class:QueryOQL') => 'QueryOQL', \$this->Add('sub_form_property', 'SubFormFor__SubFormTest__sub_form_property', [
\Dict::S('Class:SynchroAttExtKey') => 'SynchroAttExtKey', 'label' => 'UI:SubForm:Title',
\Dict::S('Class:SynchroAttLinkSet') => 'SynchroAttLinkSet', ]);
\Dict::S('Class:SynchroAttribute') => 'SynchroAttribute', }
\Dict::S('Class:SynchroDataSource') => 'SynchroDataSource', }
\Dict::S('Class:SynchroLog') => 'SynchroLog', PHP,
\Dict::S('Class:SynchroReplica') => 'SynchroReplica',
\Dict::S('Class:TriggerOnAttachmentCreate') => 'TriggerOnAttachmentCreate',
\Dict::S('Class:TriggerOnAttachmentDelete') => 'TriggerOnAttachmentDelete',
\Dict::S('Class:TriggerOnAttachmentDownload') => 'TriggerOnAttachmentDownload',
\Dict::S('Class:TriggerOnAttributeBlobDownload') => 'TriggerOnAttributeBlobDownload',
\Dict::S('Class:TriggerOnObjectCreate') => 'TriggerOnObjectCreate',
\Dict::S('Class:TriggerOnObjectDelete') => 'TriggerOnObjectDelete',
\Dict::S('Class:TriggerOnObjectMention') => 'TriggerOnObjectMention',
\Dict::S('Class:TriggerOnObjectUpdate') => 'TriggerOnObjectUpdate',
\Dict::S('Class:TriggerOnPortalUpdate') => 'TriggerOnPortalUpdate',
\Dict::S('Class:TriggerOnStateEnter') => 'TriggerOnStateEnter',
\Dict::S('Class:TriggerOnStateLeave') => 'TriggerOnStateLeave',
\Dict::S('Class:TriggerOnThresholdReached') => 'TriggerOnThresholdReached',
\Dict::S('Class:URP_Profiles') => 'URP_Profiles',
\Dict::S('Class:URP_UserOrg') => 'URP_UserOrg',
\Dict::S('Class:UserExternal') => 'UserExternal',
\Dict::S('Class:UserLDAP') => 'UserLDAP',
\Dict::S('Class:UserLocal') => 'UserLocal',
], ],
'Collection of values' => [
'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_typeproperty_type id="CollectionOfValuesTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="coll" xsi:type="Combodo-ValueType-CollectionOfValues">
<label>UI:ClassAttributeValue</label>
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
<class>Contact</class>
<attribute>status</attribute>
</value-type>
</node>
</nodes>
</definition>
</property_typeproperty_type>
XML,
'sExpectedPHP' => <<<PHP
class FormFor__CollectionOfValuesTest extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
\$this->Add('coll', 'Combodo\iTop\Forms\Block\DataModel\AttributeValueChoiceFormBlock', [
'label' => 'UI:ClassAttributeValue',
'multiple' => true,
]); ]);
} }
} }
@@ -613,10 +605,13 @@ PHP,
'test' => [ 'test' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="Test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_typeproperty_type id="Test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
</nodes> </nodes>
</node> </definition>
</property_typeproperty_type>
XML, XML,
'sExpectedPHP' => <<<PHP 'sExpectedPHP' => <<<PHP
class FormFor__Test extends Combodo\iTop\Forms\Block\Base\FormBlock class FormFor__Test extends Combodo\iTop\Forms\Block\Base\FormBlock
@@ -631,20 +626,21 @@ PHP,
/** /**
* @dataProvider CompileFormFromInvalidXMLProvider * @dataProvider CompileFormFromInvalidXMLProvider
*
* @param string $sXMLContent * @param string $sXMLContent
* @param string $sExpectedClass * @param string $sExpectedClass
* @param string $sExpectedMessage * @param string $sExpectedMessage
* *
* @return void * @return void
* @throws \Combodo\iTop\Forms\Compiler\FormsCompilerException * @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException * @throws \Combodo\iTop\PropertyType\PropertyTypeException
* @throws \DOMFormatException * @throws \DOMFormatException
*/ */
public function testCompileFormFromInvalidXML(string $sXMLContent, string $sExpectedClass, string $sExpectedMessage) public function testCompileFormFromInvalidXML(string $sXMLContent, string $sExpectedClass, string $sExpectedMessage)
{ {
$this->expectException($sExpectedClass); $this->expectException($sExpectedClass);
$this->expectExceptionMessage($sExpectedMessage); $this->expectExceptionMessage($sExpectedMessage);
FormsCompiler::GetInstance()->CompileFormFromXML($sXMLContent); PropertyTypeCompiler::GetInstance()->CompileFormFromXML($sXMLContent);
} }
public function CompileFormFromInvalidXMLProvider() public function CompileFormFromInvalidXMLProvider()
@@ -653,99 +649,120 @@ PHP,
'Invalid OQL expression in condition' => [ 'Invalid OQL expression in condition' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="dependant_property"> <node id="dependant_property" xsi:type="Combodo-ValueType-String">
<label>UI:Dependant</label> <label>UI:Dependant</label>
<relevance-condition>{{source_property.text == 'count'}}</relevance-condition> <relevance-condition>{{source_property.text == 'count'}}</relevance-condition>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedClass' => 'Combodo\iTop\PropertyTree\PropertyTreeException', 'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
'sExpectedMessage' => 'Node: dependant_property, invalid syntax in condition: Unexpected token EQ - found \'=\' at 22 in \'source_property.text == \'count\'\'', 'sExpectedMessage' => 'Node: dependant_property, invalid syntax in condition: Unexpected token EQ - found \'=\' at 22 in \'source_property.text == \'count\'\'',
], ],
'Unknown source in relevance condition' => [ 'Unknown source in relevance condition' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="dependant_property"> <node id="dependant_property" xsi:type="Combodo-ValueType-String">
<label>UI:Dependant</label> <label>UI:Dependant</label>
<relevance-condition>{{source_property.text = 'count'}}</relevance-condition> <relevance-condition>{{source_property.text = 'count'}}</relevance-condition>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedClass' => 'Combodo\iTop\PropertyTree\PropertyTreeException', 'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
'sExpectedMessage' => 'Node: dependant_property, invalid source in condition: source_property', 'sExpectedMessage' => 'Node: dependant_property, invalid source in condition: source_property',
], ],
'Unknown output in relevance condition' => [ 'Unknown output in relevance condition' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="source_property"> <node id="source_property" xsi:type="Combodo-ValueType-String">
<label>UI:Source</label> <label>UI:Source</label>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
<node id="dependant_property"> <node id="dependant_property" xsi:type="Combodo-ValueType-String">
<label>UI:Dependant</label> <label>UI:Dependant</label>
<relevance-condition>{{source_property.text_output != 'count'}}</relevance-condition> <relevance-condition>{{source_property.text_output != 'count'}}</relevance-condition>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedClass' => 'Combodo\iTop\PropertyTree\PropertyTreeException', 'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
'sExpectedMessage' => 'Node: dependant_property, invalid output in condition: source_property.text_output', 'sExpectedMessage' => 'Node: dependant_property, invalid output in condition: source_property.text_output',
], ],
'Missing output or source in relevance condition' => [ 'Missing output or source in relevance condition' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="source_property"> <node id="source_property" xsi:type="Combodo-ValueType-String">
<label>UI:Source</label> <label>UI:Source</label>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
<node id="dependant_property"> <node id="dependant_property" xsi:type="Combodo-ValueType-String">
<label>UI:Dependant</label> <label>UI:Dependant</label>
<relevance-condition>{{source_property != 'count'}}</relevance-condition> <relevance-condition>{{source_property != 'count'}}</relevance-condition>
<value-type xsi:type="Combodo-ValueType-String">
</value-type>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedClass' => 'Combodo\iTop\PropertyTree\PropertyTreeException', 'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
'sExpectedMessage' => 'Node: dependant_property, missing output or source in condition: source_property', 'sExpectedMessage' => 'Node: dependant_property, missing output or source in condition: source_property',
], ],
'Missing value-type in node specification' => [ 'Missing value-type in node specification' => [
'sXMLContent' => <<<XML 'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<node id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3"> <property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes> <nodes>
<node id="source_property"> <node id="source_property">
<label>UI:Source</label> <label>UI:Source</label>
</node> </node>
</nodes> </nodes>
</node> </definition>
</property_type>
XML, XML,
'sExpectedClass' => 'Combodo\iTop\PropertyTree\PropertyTreeException', 'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
'sExpectedMessage' => 'Node: source_property, missing value-type in node specification', 'sExpectedMessage' => 'Node: source_property, missing value-type in node specification',
], ],
'Wrong class for value-type in node specification' => [
'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="source_property" xsi:type="Test-Combodo">
<label>UI:Source</label>
</node>
</nodes>
</definition>
</property_type>
XML,
'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
'sExpectedMessage' => 'Node: source_property, unknown type node class: "Test-Combodo"',
],
]; ];
} }
} }

View File

@@ -0,0 +1,331 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\PropertyType\Compiler\PropertyTypeCompiler;
use Combodo\iTop\PropertyType\PropertyTypeDesign;
use Combodo\iTop\Service\DependencyInjection\ServiceLocator;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
class XMLSerializerTest extends ItopDataTestCase
{
/**
* @dataProvider XMLSerializerProvider
*
* @param $inputContent
* @param string $sPropertyTypeXML
* @param string $sExpectedXMLContent
*
* @return void
* @throws \DOMException
*/
public function testSerializeXML($inputContent, string $sPropertyTypeXML, string $sExpectedXMLContent)
{
ServiceLocator::GetInstance()->RegisterService('ModelReflection', new ModelReflectionRuntime());
$oDOMDocument = new PropertyTypeDesign();
$oDOMDocument->preserveWhiteSpace = false;
$oDOMDocument->formatOutput = true;
/** @var \Combodo\iTop\DesignElement $oRootNode */
$oRootNode = $oDOMDocument->createElement('root');
$oDOMDocument->appendChild($oRootNode);
Combodo\iTop\PropertyType\Serializer\XMLSerializer::GetInstance()->SerializeForPropertyType($inputContent, $oRootNode, $sPropertyTypeXML);
$sActualXML = $oDOMDocument->saveXML();
$this->AssertEqualiTopXML($sExpectedXMLContent, $sActualXML);
}
public function XMLSerializerProvider()
{
return [
'Basic test should serialize to XML' => [
'inputContent' => 'text',
'sPropertyTypeXML' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-Label">
</definition>
</property_type>
XML,
'sExpectedXMLContent' => <<<XML
<?xml version="1.0"?>
<root>text</root>
XML,
],
'Collection of values as CSV' => [
'inputContent' => ['Contact', 'Organization'],
'sPropertyTypeXML' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-CollectionOfValues">
<xml-format xsi:type="Combodo-XMLFormat-CSV"/>
<value-type xsi:type="Combodo-ValueType-Class">
</value-type>
</definition>
</property_type>
XML,
'sExpectedXMLContent' => <<<XML
<?xml version="1.0"?>
<root>Contact,Organization</root>
XML,
],
'Collection of values as id attribute' => [
'inputContent' => ['Contact', 'Organization'],
'sPropertyTypeXML' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="class_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-CollectionOfValues">
<xml-format xsi:type="Combodo-XMLFormat-ValueAsId">
<tag-name>item</tag-name>
</xml-format>
<value-type xsi:type="Combodo-ValueType-Class">
</value-type>
</definition>
</property_type>
XML,
'sExpectedXMLContent' => <<<XML
<?xml version="1.0"?>
<root>
<item id="Contact"/>
<item id="Organization"/>
</root>
XML,
],
'Collection of tree as flat array' => [
'inputContent' => [
[
'title_property' => 'title_a',
'class_property' => 'class_a',
],
[
'title_property' => 'title_b',
'class_property' => 'class_b',
],
],
'sPropertyTypeXML' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="collection_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-Collection">
<xml-format xsi:type="Combodo-XMLFormat-FlatArray">
<count-tag>item_count</count-tag>
<tag-format>item_\$rank\$_\$id\$</tag-format>
</xml-format>
<prototype>
<node id="title_property" xsi:type="Combodo-ValueType-Label">
<label>UI:BasicTest:Prop-Title</label>
</node>
<node id="class_property" xsi:type="Combodo-ValueType-Class">
<label>UI:BasicTest:Prop-Class</label>
<categories-csv>test</categories-csv>
</node>
</prototype>
</definition>
</property_type>
XML,
'sExpectedXMLContent' => <<<XML
<?xml version="1.0"?>
<root>
<item_count>2</item_count>
<item_0_title_property>title_a</item_0_title_property>
<item_0_class_property>class_a</item_0_class_property>
<item_1_title_property>title_b</item_1_title_property>
<item_1_class_property>class_b</item_1_class_property>
</root>
XML,
],
'Property tree' => [
'inputContent' => ['title_property' => 'title', 'class_property' => 'class'],
'sPropertyTypeXML' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="property_tree_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="title_property" xsi:type="Combodo-ValueType-Label">
<label>UI:BasicTest:Prop-Title</label>
</node>
<node id="class_property" xsi:type="Combodo-ValueType-Class">
<label>UI:BasicTest:Prop-Class</label>
<categories-csv>test</categories-csv>
</node>
</nodes>
</definition>
</property_type>
XML,
'sExpectedXMLContent' => <<<XML
<?xml version="1.0"?>
<root>
<title_property>title</title_property>
<class_property>class</class_property>
</root>
XML,
],
];
}
/**
* @dataProvider XMLUnserializerProvider
*
* @param $sInputXMLContent
* @param string $sPropertyTypeXML
* @param $expectedValue
*
* @return void
*/
public function testUnserializeXML($sInputXMLContent, string $sPropertyTypeXML, $expectedValue)
{
ServiceLocator::GetInstance()->RegisterService('ModelReflection', new ModelReflectionRuntime());
$oDoc = new PropertyTypeDesign();
$oDoc->loadXML($sInputXMLContent);
/** @var \Combodo\iTop\DesignElement $oRoot */
$oRoot = $oDoc->firstChild;
$aActualValue = Combodo\iTop\PropertyType\Serializer\XMLSerializer::GetInstance()->UnserializeForPropertyType($oRoot, $sPropertyTypeXML);
$this->assertEquals($expectedValue, $aActualValue);
}
public function XMLUnserializerProvider()
{
return [
'Basic test should unserialize from XML' => [
'sInputXMLContent' => <<<XML
<?xml version="1.0"?>
<root>text</root>
XML,
'sPropertyTypeXML' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-Label">
</definition>
</property_type>
XML,
'expectedValue' => 'text',
],
'Collection of values as CSV' => [
'sInputXMLContent' => <<<XML
<?xml version="1.0"?>
<root>Contact,Organization</root>
XML,
'sPropertyTypeXML' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-CollectionOfValues">
<xml-format xsi:type="Combodo-XMLFormat-CSV"/>
<value-type xsi:type="Combodo-ValueType-Class">
</value-type>
</definition>
</property_type>
XML,
'expectedValue' => ['Contact', 'Organization'],
],
'Collection of values as id attribute' => [
'sInputXMLContent' => <<<XML
<?xml version="1.0"?>
<root>
<item id="Contact"/>
<item id="Organization"/>
</root>
XML,
'sPropertyTypeXML' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="class_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-CollectionOfValues">
<xml-format xsi:type="Combodo-XMLFormat-ValueAsId">
<tag-name>item</tag-name>
</xml-format>
<value-type xsi:type="Combodo-ValueType-Class">
</value-type>
</definition>
</property_type>
XML,
'expectedValue' => ['Contact', 'Organization'],
],
'Collection of tree as flat array' => [
'sInputXMLContent' => <<<XML
<?xml version="1.0"?>
<root>
<item_count>2</item_count>
<item_0_title_property>title_a</item_0_title_property>
<item_0_class_property>class_a</item_0_class_property>
<item_1_title_property>title_b</item_1_title_property>
<item_1_class_property>class_b</item_1_class_property>
</root>
XML,
'sPropertyTypeXML' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="collection_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-Collection">
<xml-format xsi:type="Combodo-XMLFormat-FlatArray">
<count-tag>item_count</count-tag>
<tag-format>item_\$rank\$_\$id\$</tag-format>
</xml-format>
<prototype>
<node id="title_property" xsi:type="Combodo-ValueType-Label">
<label>UI:BasicTest:Prop-Title</label>
</node>
<node id="class_property" xsi:type="Combodo-ValueType-Class">
<label>UI:BasicTest:Prop-Class</label>
<categories-csv>test</categories-csv>
</node>
</prototype>
</definition>
</property_type>
XML,
'expectedValue' => [
[
'title_property' => 'title_a',
'class_property' => 'class_a',
],
[
'title_property' => 'title_b',
'class_property' => 'class_b',
],
],
],
'Property tree' => [
'sInputXMLContent' => <<<XML
<?xml version="1.0"?>
<root>
<title_property>title</title_property>
<class_property>class</class_property>
</root>
XML,
'sPropertyTypeXML' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<property_type id="property_tree_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="title_property" xsi:type="Combodo-ValueType-Label">
<label>UI:BasicTest:Prop-Title</label>
</node>
<node id="class_property" xsi:type="Combodo-ValueType-Class">
<label>UI:BasicTest:Prop-Class</label>
<categories-csv>test</categories-csv>
</node>
</nodes>
</definition>
</property_type>
XML,
'expectedValue' => ['title_property' => 'title', 'class_property' => 'class'],
],
];
}
}

35
validation/itop-delta.xsd Normal file
View File

@@ -0,0 +1,35 @@
<?xml version="1.0"?>
<!--
~ @copyright Copyright (C) 2010-2026 Combodo SAS
~ @license http://opensource.org/licenses/AGPL-3.0
-->
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
>
<!-- ===================== Lazy validation in the first place ===================== -->
<xsd:complexType name="Combodo-Anything">
<xsd:sequence>
<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
</xsd:sequence>
<xsd:attribute name="version" type="xsd:string"/>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="_delta" type="itop-delta-flag"/>
</xsd:complexType>
<!-- ============================= Reusable components =============================== -->
<xsd:simpleType name="itop-delta-flag" final="restriction" >
<xsd:restriction base="xsd:string">
<xsd:enumeration value="merge" />
<xsd:enumeration value="if_exists" />
<xsd:enumeration value="must_exist" />
<xsd:enumeration value="define" />
<xsd:enumeration value="define_if_not_exists" />
<xsd:enumeration value="redefine" />
<xsd:enumeration value="force" />
<xsd:enumeration value="delete" />
<xsd:enumeration value="delete_if_exists" />
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
>
<xsd:include schemaLocation="itop-delta.xsd"/>
<xsd:include schemaLocation="property_types.xsd"/>
<!-- ===================== Lazy validation in the first place ===================== -->
<xsd:element name="itop_design" type="Combodo-Anything"/>
<!-- ===================== Get rid of errors for still unhandled types ===================== -->
<xsd:complexType name="AttributeString">
<xsd:complexContent>
<xsd:extension base="Combodo-Anything"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="AttributeExternalKey">
<xsd:complexContent>
<xsd:extension base="Combodo-Anything"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="AttributeDateTime">
<xsd:complexContent>
<xsd:extension base="Combodo-Anything"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="MenuGroup">
<xsd:complexContent>
<xsd:extension base="Combodo-Anything"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="DashboardMenuNode">
<xsd:complexContent>
<xsd:extension base="Combodo-Anything"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="ShortcutContainerMenuNode">
<xsd:complexContent>
<xsd:extension base="Combodo-Anything"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="TemplateMenuNode">
<xsd:complexContent>
<xsd:extension base="Combodo-Anything"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="OQLMenuNode">
<xsd:complexContent>
<xsd:extension base="Combodo-Anything"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="WebPageMenuNode">
<xsd:complexContent>
<xsd:extension base="Combodo-Anything"/>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,400 @@
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
>
<xsd:include schemaLocation="itop-delta.xsd"/>
<xsd:complexType name="Combodo-AbstractAbstractPropertyType" abstract="true">
<xsd:attribute name="id" type="xsd:string" use="required"/>
<xsd:attribute name="_delta" type="itop-delta-flag"/>
</xsd:complexType>
<xsd:complexType name="Combodo-AbstractPropertyType"> <!-- not abstract! -->
<xsd:complexContent>
<xsd:extension base="Combodo-AbstractAbstractPropertyType">
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-PropertyType">
<xsd:complexContent>
<xsd:extension base="Combodo-AbstractAbstractPropertyType">
<xsd:sequence>
<xsd:element name="extends" type="xsd:string"/>
<xsd:element name="definition" type="Combodo-ValueType-Abstract"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!--============================= Internal types ===============================-->
<xsd:simpleType name="itop-tag" id="itop-tag">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Za-z][A-Za-z_0-9]*"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:attributeGroup name="attribute-itop-tag-as-id">
<xsd:attribute name="id" type="itop-tag" use="required">
<xsd:annotation>
<xsd:documentation>Name of the tag in the target XML delta. Should be lower case, separated by underscores</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:attributeGroup>
<xsd:simpleType name="dictentry-or-string">
<xsd:annotation>
<xsd:documentation>Dictionary entry or string</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
<xsd:complexType name="class-name-or-ref">
<xsd:annotation>
<xsd:appinfo>Example: "{{query1.class}}"</xsd:appinfo>
<xsd:documentation>Reference to the class to</xsd:documentation>
</xsd:annotation>
<xsd:simpleContent>
<xsd:extension base="xsd:string"/>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="label-and-value">
<xsd:sequence>
<xsd:element name="label" type="dictentry-or-string"/>
<xsd:element name="value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<!--============================= Scalar Value types ===============================-->
<xsd:complexType name="Combodo-ValueType-Abstract">
<xsd:sequence>
<xsd:element name="label" minOccurs="0" type="xsd:string"/>
<xsd:element name="usage" minOccurs="0">
<xsd:annotation>
<xsd:documentation>When to use this tag (always, never, optional...)</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="optional"/>
<xsd:enumeration value="required"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="relevance-condition" minOccurs="0">
<xsd:annotation>
<xsd:documentation>OQL Expression, with each sibling value as a parameter like in "{{query.selected_class = 'Ticket'}}"</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="id" type="itop-tag"/> <!-- Sometimes mandatory, sometimes optional... could not manage to handle both cases, thus I've left it as a lazy validation -->
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-Leaf">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Abstract">
<xsd:sequence>
<xsd:element name="xml-format" minOccurs="0" type="Combodo-XMLFormat-Abstract">
<xsd:annotation>
<xsd:documentation>Format of the property in the source XML</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-Label">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
<xsd:element name="min-length" minOccurs="0" type="xsd:positiveInteger"/>
<xsd:element name="max-length" minOccurs="0" type="xsd:positiveInteger"/>
<xsd:element name="not-blank" minOccurs="0"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-String">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
<xsd:element name="min-length" minOccurs="0" type="xsd:positiveInteger"/>
<xsd:element name="max-length" minOccurs="0" type="xsd:positiveInteger"/>
<xsd:element name="not-blank" minOccurs="0"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-Text">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-String">
<xsd:sequence>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-Choice">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
<xsd:element name="values" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="label" type="dictentry-or-string"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-ChoiceFromInput">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
<xsd:element name="values" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="label" type="dictentry-or-string"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-Integer">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-Boolean">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
<xsd:element name="on" type="label-and-value">
<xsd:annotation>
<xsd:documentation>Value representing "true"</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="off" type="label-and-value">
<xsd:annotation>
<xsd:documentation>Value representing "false"</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-OQL">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-Class">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
<xsd:element name="categories-csv" type="xsd:string" minOccurs="0">
<xsd:annotation>
<xsd:appinfo>Example: "bizmodel,structure"</xsd:appinfo>
<xsd:documentation>Categories of classes to propose (union)</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-ClassAttribute">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
<xsd:element name="class" type="class-name-or-ref"/>
<xsd:element name="category" maxOccurs="unbounded">
<xsd:annotation>
<xsd:appinfo>Example: "groupable"</xsd:appinfo>
<xsd:documentation>Category of attributes to propose</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:NMTOKEN">
<xsd:enumeration value="groupable"/>
<xsd:enumeration value="displayable"/>
<xsd:enumeration value="numeric"/>
<xsd:enumeration value="enum"/>
<xsd:enumeration value="date"/>
<xsd:enumeration value="link"/>
<xsd:enumeration value="string"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-ClassAttributeGroupBy">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
<xsd:element name="class" type="class-name-or-ref"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-AggregateFunction">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
<xsd:element name="class" type="class-name-or-ref"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-ClassAttributeValue">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
<xsd:element name="class" type="class-name-or-ref"/>
<xsd:element name="attribute"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-ProfileName">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-Icon">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Leaf">
<xsd:sequence>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!--============================= Complex value types ===============================-->
<xsd:complexType name="Combodo-ValueType-PropertyTree">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Abstract">
<xsd:sequence>
<xsd:element name="nodes">
<xsd:complexType>
<xsd:sequence>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="node" type="Combodo-ValueType-Abstract">
</xsd:element>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-Collection">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Abstract">
<xsd:sequence>
<xsd:element name="xml-format" minOccurs="0" type="Combodo-XMLFormat-Abstract">
<xsd:annotation>
<xsd:documentation>Format of the property in the source XML</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="prototype">
<xsd:complexType>
<xsd:sequence>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="node" type="Combodo-ValueType-Abstract"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-ValueType-CollectionOfValues">
<xsd:complexContent>
<xsd:extension base="Combodo-ValueType-Abstract">
<xsd:sequence>
<xsd:element name="xml-format" minOccurs="0" type="Combodo-XMLFormat-Abstract">
<xsd:annotation>
<xsd:documentation>Format of the property in the source XML</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="value-type" type="Combodo-ValueType-Leaf"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!--============================= XML Formats ===============================-->
<xsd:complexType name="Combodo-XMLFormat-Abstract">
<xsd:sequence>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Combodo-XMLFormat-CSV">
<xsd:complexContent>
<xsd:extension base="Combodo-XMLFormat-Abstract">
<xsd:sequence>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-XMLFormat-ValueAsId">
<xsd:complexContent>
<xsd:extension base="Combodo-XMLFormat-Abstract">
<xsd:sequence>
<xsd:element name="tag-name" type="xsd:NCName"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Combodo-XMLFormat-FlatArray">
<xsd:complexContent>
<xsd:extension base="Combodo-XMLFormat-Abstract">
<xsd:sequence>
<xsd:element name="count-tag" type="xsd:NCName">
<xsd:annotation>
<xsd:documentation>Tag to hold the number of items in the collection</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="tag-format" type="xsd:string">
<xsd:annotation>
<xsd:documentation>Template to generate tag name for the sub-nodes. Available placeholders: $id$ and $rank$</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>