diff --git a/src/SchemaReader.php b/src/SchemaReader.php index 651c5f9f..6d42222c 100644 --- a/src/SchemaReader.php +++ b/src/SchemaReader.php @@ -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 = ( @@ -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, @@ -356,13 +363,15 @@ function ( DOMElement $childNode ) use ( $elementContainer, - $max + $max, + $min ): void { $this->loadSequenceChildNode( $elementContainer, $node, $childNode, - $max + $max, + $min ); } ); @@ -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': @@ -381,7 +391,8 @@ private function loadSequenceChildNode( $this->loadSequence( $elementContainer, $childNode, - $max + $max, + $min ); break; case 'element': @@ -389,7 +400,8 @@ private function loadSequenceChildNode( $elementContainer, $node, $childNode, - $max + $max, + $min ); break; case 'group': @@ -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')); @@ -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, diff --git a/tests/TypesTest.php b/tests/TypesTest.php index 3934fb54..4211de55 100644 --- a/tests/TypesTest.php +++ b/tests/TypesTest.php @@ -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( + ' + + + + + + + '); + + $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( + ' + + + + + + + '); + + $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 [