N°8772 - test driven compiler wip

This commit is contained in:
Eric Espie
2025-12-10 16:21:31 +01:00
parent 090925e28b
commit c40e7ab10e
13 changed files with 402 additions and 54 deletions

View File

@@ -568,6 +568,7 @@ return array(
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeLabel' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeLabel.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeOQL' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeOQL.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeProfileName' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeProfileName.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeString' => $baseDir . '/sources/PropertyTree/ValueType/ValueTypeString.php',
'Combodo\\iTop\\Renderer\\BlockRenderer' => $baseDir . '/sources/Renderer/BlockRenderer.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => $baseDir . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => $baseDir . '/sources/Renderer/Bootstrap/BsFormRenderer.php',

View File

@@ -954,6 +954,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeLabel' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeLabel.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeOQL' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeOQL.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeProfileName' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeProfileName.php',
'Combodo\\iTop\\PropertyTree\\ValueType\\ValueTypeString' => __DIR__ . '/../..' . '/sources/PropertyTree/ValueType/ValueTypeString.php',
'Combodo\\iTop\\Renderer\\BlockRenderer' => __DIR__ . '/../..' . '/sources/Renderer/BlockRenderer.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFormRenderer' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFormRenderer.php',

View File

@@ -40,6 +40,8 @@ class FormsCompiler
*
* @return string
* @throws \Combodo\iTop\Forms\Compiler\FormsCompilerException
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
* @throws \DOMFormatException
*/
public function CompileFormFromXML(string $sXMLContent): string
{
@@ -54,8 +56,8 @@ class FormsCompiler
/** @var \Combodo\iTop\DesignElement $oRoot */
$oRoot = $oDoc->firstChild;
$oPropertyTree = PropertyTreeFactory::GetInstance()->CreateNodeFromDom($oRoot);
$sPHP = $oPropertyTree->ToPHP();
return $sPHP;
return $oPropertyTree->ToPHPFormBlock();
}
public function StoreFormFromContent(string $sId, string $sPHPContent): void

View File

@@ -9,6 +9,7 @@ namespace Combodo\iTop\PropertyTree;
use Combodo\iTop\DesignElement;
use Combodo\iTop\PropertyTree\ValueType\AbstractValueType;
use utils;
/**
* @since 3.3.0
@@ -19,16 +20,32 @@ abstract class AbstractProperty
protected ?string $sLabel;
/** @var array<AbstractProperty> */
protected array $aChildren;
protected array $aChildren = [];
protected ?AbstractValueType $oValueType;
protected ?string $sParentId;
public function InitFromDomNode(DesignElement $oDomNode)
/**
* 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, string $sParentId = ''): void
{
$this->sId = $oDomNode->getAttribute('id');
if (utils::IsNotNullOrEmptyString($sParentId)) {
$this->sId = $sParentId.'__';
} else {
$this->sId = '';
}
$this->sId .= $oDomNode->getAttribute('id');
$this->sLabel = $oDomNode->GetChildText('label');
}
abstract public function ToPHP(&$aPHPFragments = []): string;
abstract public function ToPHPFormBlock(&$aPHPFragments = []): string;
public function GetValueType(): ?AbstractValueType
{

View File

@@ -7,13 +7,69 @@
namespace Combodo\iTop\PropertyTree;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\Base\CollectionBlock;
/**
* @since 3.3.0
*/
class CollectionOfTrees extends AbstractProperty
{
public function ToPHP(&$aPHPFragments = []): string
protected ?string $sButtonLabel;
/**
* @inheritDoc
*/
public function InitFromDomNode(DesignElement $oDomNode, string $sParentId = ''): void
{
return '';
parent::InitFromDomNode($oDomNode, $sParentId);
$oPropertyTreeFactory = PropertyTreeFactory::GetInstance();
$this->sButtonLabel = $oDomNode->GetChildText('button-label');
// read child properties
foreach ($oDomNode->GetUniqueElement('prototype')->childNodes as $oNode) {
if ($oNode instanceof DesignElement) {
$this->AddChild($oPropertyTreeFactory->CreateNodeFromDom($oNode, $this->sId));
}
}
}
public function ToPHPFormBlock(&$aPHPFragments = []): string
{
$sFormBlockClass = CollectionBlock::class;
$sSubTreeClass = 'SubFormFor__'.$this->sId;
// Create the collection node
$sLocalPHP = <<<PHP
\$this->Add('$this->sId', '$sFormBlockClass', [
'label' => '$this->sLabel',
'button_label' => '$this->sButtonLabel',
'block_entry_type' => '$sSubTreeClass',
]);
PHP;
$sSubClassPHP = <<<PHP
class SubFormFor__$this->sId extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
PHP;
foreach ($this->aChildren as $oProperty) {
$sSubClassPHP .= "\n".$oProperty->ToPHPFormBlock($aPHPFragments);
}
$sSubClassPHP .= <<<PHP
}
}
PHP;
$aPHPFragments[] = $sSubClassPHP;
return $sLocalPHP;
}
}

View File

@@ -12,7 +12,7 @@ namespace Combodo\iTop\PropertyTree;
*/
class CollectionOfValues extends AbstractProperty
{
public function ToPHP(&$aPHPFragments = []): string
public function ToPHPFormBlock(&$aPHPFragments = []): string
{
return '';
}

View File

@@ -16,13 +16,9 @@ use Combodo\iTop\PropertyTree\ValueType\ValueTypeFactory;
class Property extends AbstractProperty
{
/**
* @param \Combodo\iTop\DesignElement $oDomNode
*
* @return void
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
* @throws \DOMFormatException
* @inheritDoc
*/
public function InitFromDomNode(DesignElement $oDomNode): void
public function InitFromDomNode(DesignElement $oDomNode, string $sParentId = ''): void
{
parent::InitFromDomNode($oDomNode);
@@ -32,7 +28,7 @@ class Property extends AbstractProperty
}
}
public function ToPHP(&$aPHPFragments = []): string
public function ToPHPFormBlock(&$aPHPFragments = []): string
{
$sFormBlockClass = $this->oValueType->GetFormBlockClass();
return <<<PHP

View File

@@ -15,37 +15,33 @@ use Combodo\iTop\DesignElement;
class PropertyTree extends AbstractProperty
{
/**
* @param \Combodo\iTop\DesignElement $oDomNode
*
* @return void
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
* @throws \DOMFormatException
* @inheritdoc
*/
public function InitFromDomNode(DesignElement $oDomNode): void
public function InitFromDomNode(DesignElement $oDomNode, string $sParentId = ''): void
{
parent::InitFromDomNode($oDomNode);
$oPropertyTreeService = PropertyTreeFactory::GetInstance();
parent::InitFromDomNode($oDomNode, $sParentId);
$oPropertyTreeFactory = PropertyTreeFactory::GetInstance();
// read child properties
foreach ($oDomNode->GetUniqueElement('nodes')->childNodes as $oNode) {
if ($oNode instanceof DesignElement) {
$this->AddChild($oPropertyTreeService->CreateNodeFromDom($oNode));
$this->AddChild($oPropertyTreeFactory->CreateNodeFromDom($oNode, $this->sId));
}
}
}
public function ToPHP(&$aPHPFragments = []): string
public function ToPHPFormBlock(&$aPHPFragments = []): string
{
$bIsRoot = (count($aPHPFragments) === 0);
$sLocalPHP = <<<PHP
class FormFor$this->sId extends Combodo\iTop\Forms\Block\Base\FormBlock
class FormFor__$this->sId extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
PHP;
foreach ($this->aChildren as $oProperty) {
$sLocalPHP .= "\n".$oProperty->ToPHP($aPHPFragments);
$sLocalPHP .= "\n".$oProperty->ToPHPFormBlock($aPHPFragments);
}
$sLocalPHP .= <<<PHP

View File

@@ -9,6 +9,7 @@ namespace Combodo\iTop\PropertyTree;
use Combodo\iTop\DesignDocument;
use Combodo\iTop\DesignElement;
use utils;
class PropertyTreeFactory
{
@@ -31,17 +32,20 @@ class PropertyTreeFactory
* Create a property node from a design element
*
* @param \Combodo\iTop\DesignElement $oDomNode
* @param string $sParentId
*
* @return \Combodo\iTop\PropertyTree\AbstractProperty
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
* @throws \DOMFormatException
*/
public function CreateNodeFromDom(DesignElement $oDomNode): AbstractProperty
public function CreateNodeFromDom(DesignElement $oDomNode, string $sParentId = ''): AbstractProperty
{
$sNodeType = $oDomNode->getAttribute('xsi:type');
// The class of the property tree node is given by the xsi:type attribute
if (is_a($sNodeType, AbstractProperty::class, true)) {
$oNode = new $sNodeType();
$oNode->InitFromDomNode($oDomNode);
$oNode->InitFromDomNode($oDomNode, $sParentId);
return $oNode;
}

View File

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

View File

@@ -102,10 +102,13 @@ class_alias(\Combodo\iTop\PropertyTree\Property::class, 'Combodo-Property');
class_alias(\Combodo\iTop\PropertyTree\CollectionOfValues::class, 'Combodo-CollectionOfValues');
class_alias(\Combodo\iTop\PropertyTree\CollectionOfTrees::class, 'Combodo-CollectionOfTrees');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeAggregateFunction::class, 'Combodo-ValueTypeAggregateFunction');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeChoice::class, 'Combodo-ValueTypeChoice');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClass::class, 'Combodo-ValueTypeClass');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClassAttribute::class, 'Combodo-ValueTypeClassAttribute');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClassAttributeGroupBy::class, 'Combodo-ValueTypeClassAttributeGroupBy');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClassAttributeValue::class, 'Combodo-ValueTypeClassAttributeValue');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeInteger::class, 'Combodo-ValueTypeInteger');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeLabel::class, 'Combodo-ValueTypeLabel');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeOQL::class, 'Combodo-ValueTypeOQL');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClassAttributeGroupBy::class, 'Combodo-ValueTypeClassAttributeGroupBy');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeChoice::class, 'Combodo-ValueTypeChoice');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClassAttribute::class, 'Combodo-ValueTypeClassAttribute');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeInteger::class, 'Combodo-ValueTypeInteger');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeClass::class, 'Combodo-ValueTypeClass');
class_alias(\Combodo\iTop\PropertyTree\ValueType\ValueTypeString::class, 'Combodo-ValueTypeString');

View File

@@ -11,6 +11,7 @@ use CMDBSource;
use DateTime;
use DeprecatedCallsLog;
use MySQLTransactionNotClosedException;
use ParseError;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use ReflectionMethod;
use SetupUtils;
@@ -574,6 +575,23 @@ abstract class ItopTestCase extends KernelTestCase
self::assertLessThan(2, $iTimeInterval, $sMessage);
}
/**
* @since 3.3.0
*/
protected static function AssertPHPCodeIsValid(string $sPHPCode, $sMessage = ''): void
{
try {
eval($sPHPCode);
} catch (ParseError $e) {
$aLines = explode("\n", $sPHPCode);
foreach ($aLines as $iLine => $sLine) {
echo sprintf("%02d: %s\n", $iLine + 1, $sLine);
}
echo 'Parse Error: '.$e->getMessage().' at line: '.$e->getLine()."\n";
self::fail($sMessage);
}
}
/**
* Control which Kernel will be loaded when invoking the bootKernel method
*

View File

@@ -5,50 +5,286 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Forms\Block\Base\CollectionBlock;
use Combodo\iTop\Forms\Compiler\FormsCompiler;
use Combodo\iTop\ItopSdkFormDemonstrator\Form\Block\Person\PersonFormBlock;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
class TestFormsCompiler extends ItopDataTestCase
{
public function testCompileFormFromXML()
/**
* @dataProvider CompileFormFromXMLProvider
* @param string $sXMLContent
* @param string $sExpectedPHP
*
* @return void
* @throws \Combodo\iTop\Forms\Compiler\FormsCompilerException
* @throws \Combodo\iTop\PropertyTree\PropertyTreeException
*/
public function testCompileFormFromXML(string $sXMLContent, string $sExpectedPHP, string $sMessage = '')
{
$sXMLContent = <<<XML
$sProducedPHP = FormsCompiler::GetInstance()->CompileFormFromXML($sXMLContent);
$this->AssertPHPCodeIsValid($sProducedPHP);
$this->assertEquals($sExpectedPHP, $sProducedPHP, $sMessage);
}
public function CompileFormFromXMLProvider()
{
return [
'Basic properties' => [
'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<node id="DashletTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyTree">
<node 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">
<nodes>
<node id="title" xsi:type="Combodo-Property">
<label>UI:DashletTest:Prop-Title</label>
<node id="title_property" xsi:type="Combodo-Property">
<label>UI:BasicTest:Prop-Title</label>
<value-type xsi:type="Combodo-ValueTypeLabel">
</value-type>
</node>
<node id="class" xsi:type="Combodo-Property">
<label>UI:DashletTest:Prop-Class</label>
<node id="class_property" xsi:type="Combodo-Property">
<label>UI:BasicTest:Prop-Class</label>
<value-type xsi:type="Combodo-ValueTypeClass">
</value-type>
</node>
</nodes>
</node>
XML;
$sExpectedPHP = <<<PHP
class FormForDashletTest extends Combodo\iTop\Forms\Block\Base\FormBlock
XML,
'sExpectedPHP' => <<<PHP
class FormFor__basic_test extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
\$this->Add('title', 'Combodo\iTop\Forms\Block\DataModel\LabelFormBlock', [
'label' => 'UI:DashletTest:Prop-Title',
\$this->Add('title_property', 'Combodo\iTop\Forms\Block\DataModel\LabelFormBlock', [
'label' => 'UI:BasicTest:Prop-Title',
]);
\$this->Add('class', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
'label' => 'UI:DashletTest:Prop-Class',
\$this->Add('class_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
'label' => 'UI:BasicTest:Prop-Class',
]);
}
}
PHP;
PHP,
'sMessage' => 'Basic scalar properties should generate PHP',
],
$sProducedPHP = FormsCompiler::GetInstance()->CompileFormFromXML($sXMLContent);
eval($sProducedPHP);
$this->assertEquals($sExpectedPHP, $sProducedPHP);
'Empty property tree' => [
'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<node 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">
<nodes>
</nodes>
</node>
XML,
'sExpectedPHP' => <<<PHP
class FormFor__EmptyTest extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{ }
}
PHP,
'sMessage' => 'Empty property tree should generate minimal PHP',
],
'Empty property tree lower case' => [
'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<node 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">
<nodes>
</nodes>
</node>
XML,
'sExpectedPHP' => <<<PHP
class FormFor__empty_test extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{ }
}
PHP,
'sMessage' => 'Empty property tree should generate minimal PHP',
],
'Properties with all value-types' => [
'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<node 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">
<nodes>
<node id="aggregate_function_property" xsi:type="Combodo-Property">
<label>UI:AggregateFunction</label>
<value-type xsi:type="Combodo-ValueTypeAggregateFunction">
</value-type>
</node>
<node id="choice_property" xsi:type="Combodo-Property">
<label>UI:Choice</label>
<value-type xsi:type="Combodo-ValueTypeChoice">
</value-type>
</node>
<node id="class_property" xsi:type="Combodo-Property">
<label>UI:Class</label>
<value-type xsi:type="Combodo-ValueTypeClass">
</value-type>
</node>
<node id="class_attribute_property" xsi:type="Combodo-Property">
<label>UI:ClassAttribute</label>
<value-type xsi:type="Combodo-ValueTypeClassAttribute">
</value-type>
</node>
<node id="class_attribute_group_by_property" xsi:type="Combodo-Property">
<label>UI:ClassAttributeGroupBy</label>
<value-type xsi:type="Combodo-ValueTypeClassAttributeGroupBy">
</value-type>
</node>
<node id="class_attribute_value_property" xsi:type="Combodo-Property">
<label>UI:ClassAttributeValue</label>
<value-type xsi:type="Combodo-ValueTypeClassAttributeValue">
</value-type>
</node>
<node id="integer_property" xsi:type="Combodo-Property">
<label>UI:Integer</label>
<value-type xsi:type="Combodo-ValueTypeInteger">
</value-type>
</node>
<node id="label_property" xsi:type="Combodo-Property">
<label>UI:Label</label>
<value-type xsi:type="Combodo-ValueTypeLabel">
</value-type>
</node>
<node id="oql_property" xsi:type="Combodo-Property">
<label>UI:OQL</label>
<value-type xsi:type="Combodo-ValueTypeOQL">
</value-type>
</node>
<node id="string_property" xsi:type="Combodo-Property">
<label>UI:String</label>
<value-type xsi:type="Combodo-ValueTypeString">
</value-type>
</node>
</nodes>
</node>
XML,
'sExpectedPHP' => <<<PHP
class FormFor__AllValueTypesTest extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
\$this->Add('aggregate_function_property', 'Combodo\iTop\Forms\Block\DataModel\Dashlet\AggregateFunctionFormBlock', [
'label' => 'UI:AggregateFunction',
]);
\$this->Add('choice_property', 'Combodo\iTop\Forms\Block\Base\ChoiceFormBlock', [
'label' => 'UI:Choice',
]);
\$this->Add('class_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
'label' => 'UI:Class',
]);
\$this->Add('class_attribute_property', 'Combodo\iTop\Forms\Block\DataModel\AttributeChoiceFormBlock', [
'label' => 'UI:ClassAttribute',
]);
\$this->Add('class_attribute_group_by_property', 'Combodo\iTop\Forms\Block\DataModel\Dashlet\ClassAttributeGroupByFormBlock', [
'label' => 'UI:ClassAttributeGroupBy',
]);
\$this->Add('class_attribute_value_property', 'Combodo\iTop\Forms\Block\DataModel\AttributeValueChoiceFormBlock', [
'label' => 'UI:ClassAttributeValue',
]);
\$this->Add('integer_property', 'Combodo\iTop\Forms\Block\Base\IntegerFormBlock', [
'label' => 'UI:Integer',
]);
\$this->Add('label_property', 'Combodo\iTop\Forms\Block\DataModel\LabelFormBlock', [
'label' => 'UI:Label',
]);
\$this->Add('oql_property', 'Combodo\iTop\Forms\Block\DataModel\OqlFormBlock', [
'label' => 'UI:OQL',
]);
\$this->Add('string_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
'label' => 'UI:String',
]);
}
}
PHP,
'sMessage' => '',
],
'Collection of trees' => [
'sXMLContent' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<node 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">
<nodes>
<node id="sub_tree_collection" xsi:type="Combodo-CollectionOfTrees">
<label>UI:SubTree</label>
<button-label>UI:AddSubTree</button-label>
<prototype>
<node id="string_property" xsi:type="Combodo-Property">
<label>UI:String</label>
<value-type xsi:type="Combodo-ValueTypeString">
</value-type>
</node>
<node id="integer_property" xsi:type="Combodo-Property">
<label>UI:Integer</label>
<value-type xsi:type="Combodo-ValueTypeInteger">
</value-type>
</node>
</prototype>
</node>
</nodes>
</node>
XML,
'sExpectedPHP' => <<<PHP
class SubFormFor__collection_of_trees_test__sub_tree_collection extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
\$this->Add('string_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
'label' => 'UI:String',
]);
\$this->Add('integer_property', 'Combodo\iTop\Forms\Block\Base\IntegerFormBlock', [
'label' => 'UI:Integer',
]);
}
}
class FormFor__collection_of_trees_test extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{
\$this->Add('collection_of_trees_test__sub_tree_collection', 'Combodo\iTop\Forms\Block\Base\CollectionBlock', [
'label' => 'UI:SubTree',
'button_label' => 'UI:AddSubTree',
'block_entry_type' => 'SubFormFor__collection_of_trees_test__sub_tree_collection',
]);
}
}
PHP,
'sMessage' => '',
],
'test' => [
'sXMLContent' => <<<XML
<?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">
<nodes>
</nodes>
</node>
XML,
'sExpectedPHP' => <<<PHP
class FormFor__Test extends Combodo\iTop\Forms\Block\Base\FormBlock
{
protected function BuildForm(): void
{ }
}
PHP,
'sMessage' => '',
],
];
}
}