Skip to content

Commit

Permalink
handle properly minOccurs and maxOccurs in sequences
Browse files Browse the repository at this point in the history
  • Loading branch information
goetas committed Sep 29, 2022
1 parent a737a81 commit a4de23d
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 7 deletions.
32 changes: 25 additions & 7 deletions src/SchemaReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ private static function maybeSetDefault(InterfaceSetDefault $ref, DOMElement $no
}
}

private function loadSequence(ElementContainer $elementContainer, DOMElement $node, int $max = null): void
private function loadSequence(ElementContainer $elementContainer, DOMElement $node, int $max = null, int $min = null): void
{
$max =
(
Expand All @@ -348,6 +348,13 @@ private function loadSequence(ElementContainer $elementContainer, DOMElement $no
)
? 2
: null;
$min =
(
$min === null &&
!$node->hasAttribute('minOccurs')
)
? null
: (int) max((int) $min, $node->getAttribute('minOccurs'));

self::againstDOMNodeList(
$node,
Expand All @@ -356,13 +363,15 @@ function (
DOMElement $childNode
) use (
$elementContainer,
$max
$max,
$min
): void {
$this->loadSequenceChildNode(
$elementContainer,
$node,
$childNode,
$max
$max,
$min
);
}
);
Expand All @@ -372,7 +381,8 @@ private function loadSequenceChildNode(
ElementContainer $elementContainer,
DOMElement $node,
DOMElement $childNode,
? int $max
? int $max,
? int $min = null
): void {
switch ($childNode->localName) {
case 'sequence':
Expand All @@ -381,15 +391,17 @@ private function loadSequenceChildNode(
$this->loadSequence(
$elementContainer,
$childNode,
$max
$max,
$min
);
break;
case 'element':
$this->loadSequenceChildNodeLoadElement(
$elementContainer,
$node,
$childNode,
$max
$max,
$min
);
break;
case 'group':
Expand All @@ -407,7 +419,8 @@ private function loadSequenceChildNodeLoadElement(
ElementContainer $elementContainer,
DOMElement $node,
DOMElement $childNode,
? int $max
? int $max,
? int $min
): void {
if ($childNode->hasAttribute('ref')) {
$elementDef = $this->findElement($elementContainer->getSchema(), $node, $childNode->getAttribute('ref'));
Expand Down Expand Up @@ -436,6 +449,11 @@ private function loadSequenceChildNodeLoadElement(
$childNode
);
}

if ($min !== null) {
$element->setMin($min);
}

if ($max > 1) {
/*
* although one might think the typecast is not needed with $max being `? int $max` after passing > 1,
Expand Down
60 changes: 60 additions & 0 deletions tests/TypesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,66 @@ public function testElementMaxOccurences($xml, $expected)
$this->assertEquals($expected, $elements[0]->getMax());
}

/**
* @dataProvider getMinOccurencesOverride
*/
public function testSequencMinOccursOverride($xml, $expected)
{
$schema = $this->reader->readString(
'
<xs:schema targetNamespace="http://www.example.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="complexType">
<xs:sequence minOccurs="'.$xml.'" >
<xs:element name="el1" minOccurs="1" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>');

$complex = $schema->findType('complexType', 'http://www.example.com');
$elements = $complex->getElements();
$this->assertEquals($expected, $elements[0]->getMin());
}

public function getMinOccurencesOverride()
{
return [
['2', 2],
['1', 1],
['0', 0],
];
}

/**
* @dataProvider getMaxOccurencesOverride
*/
public function testSequencMaxOccursOverride($xml, $expected)
{
$schema = $this->reader->readString(
'
<xs:schema targetNamespace="http://www.example.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="complexType">
<xs:sequence maxOccurs="'.$xml.'" >
<xs:element name="el1" maxOccurs="5" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>');

$complex = $schema->findType('complexType', 'http://www.example.com');
$elements = $complex->getElements();
$this->assertEquals($expected, $elements[0]->getMax());
}

public function getMaxOccurencesOverride()
{
return [
['0', 5], //maxOccurs=0 is ignored
['1', 5],
['2', 2], // 2 in this case just means "many"
['unbounded', 2], // 2 in this case just means "many"
];
}


public function getMinOccurences()
{
return [
Expand Down

0 comments on commit a4de23d

Please sign in to comment.