Skip to content

Commit

Permalink
Merge pull request #30 from goetas-webservices/increase-coverage
Browse files Browse the repository at this point in the history
Increase coverage and improve groups handling
  • Loading branch information
goetas committed Jan 21, 2018
2 parents c51bd4f + edd94da commit 0a14320
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 74 deletions.
19 changes: 11 additions & 8 deletions src/Schema/Element/GroupRef.php
Expand Up @@ -60,18 +60,21 @@ public function getName(): string
public function getElements(): array
{
$elements = $this->wrapped->getElements();
if ($this->getMax() > 0 || $this->getMax() === -1) {

foreach ($elements as $k => $element) {
/**
* @var string $k
* @var Element|ElementRef|ElementSingle|GroupRef $e
*/
foreach ($elements as $k => $element) {
/**
* @var Element|ElementRef|ElementSingle|GroupRef $e
*/
$e = clone $element;
$e = clone $element;
if ($this->getMax() > 0 || $this->getMax() === -1) {
$e->setMax($this->getMax());
$elements[$k] = $e;
}

if ($this->getMin() > 1 && $e->getMin() === 1) {
$e->setMin($this->getMin());
}

$elements[$k] = $e;
}

return $elements;
Expand Down
157 changes: 92 additions & 65 deletions src/SchemaReader.php
Expand Up @@ -22,8 +22,8 @@
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef;
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementRef;
use GoetasWebservices\XML\XSDReader\Schema\Element\Group;
use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetMinMax;
use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef;
use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetMinMax;
use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException;
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Base;
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Extension;
Expand Down Expand Up @@ -91,6 +91,19 @@ class SchemaReader
self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd',
);

private function extractErrorMessage(): \Exception
{
$errors = array();

foreach (libxml_get_errors() as $error) {
$errors[] = sprintf("Error[%s] code %s: %s in '%s' at position %s:%s", $error->level, $error->code, trim($error->message), $error->file, $error->line, $error->column);
}
$e = new \Exception(implode('; ', $errors));
libxml_use_internal_errors(false);

return $e;
}

public function __construct(DocumentationReader $documentationReader = null)
{
if (null === $documentationReader) {
Expand Down Expand Up @@ -276,36 +289,33 @@ private function loadGroupRef(Group $referenced, DOMElement $node): GroupRef
return $ref;
}

private static function maybeSetMax(InterfaceSetMinMax $ref, DOMElement $node): InterfaceSetMinMax
private static function maybeSetMax(InterfaceSetMinMax $ref, DOMElement $node): void
{
if (
$node->hasAttribute('maxOccurs')
) {
if ($node->hasAttribute('maxOccurs')) {
$ref->setMax($node->getAttribute('maxOccurs') == 'unbounded' ? -1 : (int) $node->getAttribute('maxOccurs'));
}

return $ref;
}

private static function maybeSetMin(InterfaceSetMinMax $ref, DOMElement $node): InterfaceSetMinMax
private static function maybeSetMin(InterfaceSetMinMax $ref, DOMElement $node): void
{
if ($node->hasAttribute('minOccurs')) {
$ref->setMin((int) $node->getAttribute('minOccurs'));
if ($ref->getMin() > $ref->getMax()) {
$ref->setMax($ref->getMin());
}
}

return $ref;
}

private function loadSequence(ElementContainer $elementContainer, DOMElement $node, int $max = null): void
{
$max =
(
(is_int($max) && (bool) $max) ||
$node->getAttribute('maxOccurs') == 'unbounded' ||
$node->getAttribute('maxOccurs') > 1
)
? 2
: null;
(
(is_int($max) && (bool) $max) ||
$node->getAttribute('maxOccurs') == 'unbounded' ||
$node->getAttribute('maxOccurs') > 1
)
? 2
: null;

static::againstDOMNodeList(
$node,
Expand Down Expand Up @@ -424,34 +434,30 @@ private function loadGroup(Schema $schema, DOMElement $node): Closure
{
$group = new Group($schema, $node->getAttribute('name'));
$group->setDoc($this->getDocumentation($node));
$groupOriginal = $group;

if ($node->hasAttribute('maxOccurs')) {
/**
* @var GroupRef
*/
$group = self::maybeSetMax(new GroupRef($group), $node);
}
if ($node->hasAttribute('minOccurs')) {
/**
* @var GroupRef
*/
$group = self::maybeSetMin(
$group instanceof GroupRef ? $group : new GroupRef($group),
$node
);
if ($node->hasAttribute('maxOccurs') || $node->hasAttribute('maxOccurs')) {
$group = new GroupRef($group);

if ($node->hasAttribute('maxOccurs')) {
self::maybeSetMax($group, $node);
}
if ($node->hasAttribute('minOccurs')) {
self::maybeSetMin($group, $node);
}
}

$schema->addGroup($group);

return function () use ($group, $node) {
return function () use ($groupOriginal, $node) {
static::againstDOMNodeList(
$node,
function (DOMelement $node, DOMElement $childNode) use ($group) {
function (DOMelement $node, DOMElement $childNode) use ($groupOriginal) {
switch ($childNode->localName) {
case 'sequence':
case 'choice':
case 'all':
$this->loadSequence($group, $childNode);
$this->loadSequence($groupOriginal, $childNode);
break;
}
}
Expand Down Expand Up @@ -819,24 +825,24 @@ function (
$restriction
) {
if (
in_array(
$childNode->localName,
[
'enumeration',
'pattern',
'length',
'minLength',
'maxLength',
'minInclusive',
'maxInclusive',
'minExclusive',
'maxExclusive',
'fractionDigits',
'totalDigits',
'whiteSpace',
],
true
)
in_array(
$childNode->localName,
[
'enumeration',
'pattern',
'length',
'minLength',
'maxLength',
'minInclusive',
'maxInclusive',
'minExclusive',
'maxExclusive',
'fractionDigits',
'totalDigits',
'whiteSpace',
],
true
)
) {
$restriction->addCheck(
$childNode->localName,
Expand Down Expand Up @@ -1078,8 +1084,10 @@ private function loadImport(
}
}
};
} elseif ($namespace && !$schemaLocation && isset($this->globalSchema[$namespace])) {
$schema->addSchema($this->globalSchema[$namespace]);
} elseif ($namespace && !$schemaLocation && !empty($this->loadedSchemas[$namespace])) {
foreach ($this->loadedSchemas[$namespace] as $s) {
$schema->addSchema($s, $namespace);
}
}

$base = urldecode($node->ownerDocument->documentURI);
Expand Down Expand Up @@ -1117,9 +1125,9 @@ private function loadImportFresh(
): Closure {
return function () use ($namespace, $schema, $file) {
$dom = $this->getDOM(
isset($this->knownLocationSchemas[$file])
? $this->knownLocationSchemas[$file]
: $file
isset($this->knownLocationSchemas[$file])
? $this->knownLocationSchemas[$file]
: $file
);

$schemaNew = $this->createOrUseSchemaForNs($schema, $namespace);
Expand Down Expand Up @@ -1155,6 +1163,7 @@ public function getGlobalSchema(): Schema
$uri,
$globalSchemas[$namespace] = $schema = new Schema()
);
$this->setLoadedSchema($namespace, $schema);
if ($namespace === self::XSD_NS) {
$this->globalSchema = $schema;
}
Expand Down Expand Up @@ -1209,7 +1218,7 @@ public function readNodes(array $nodes, string $file = null)
$holderSchema = new Schema();
$holderSchema->addSchema($this->getGlobalSchema());

$this->setLoadedSchema($node, $holderSchema);
$this->setLoadedSchemaFromElement($node, $holderSchema);

$rootSchema->addSchema($holderSchema);

Expand All @@ -1234,7 +1243,7 @@ public function readNode(DOMElement $node, string $file = null): Schema
$this->setLoadedFile($file, $rootSchema);
}

$this->setLoadedSchema($node, $rootSchema);
$this->setLoadedSchemaFromElement($node, $rootSchema);

$callbacks = $this->schemaNode($rootSchema, $node);

Expand All @@ -1251,14 +1260,19 @@ public function readNode(DOMElement $node, string $file = null): Schema
public function readString(string $content, string $file = 'schema.xsd'): Schema
{
$xml = new DOMDocument('1.0', 'UTF-8');
if (!$xml->loadXML($content)) {
throw new IOException("Can't load the schema");
libxml_use_internal_errors(true);
if (!@$xml->loadXML($content)) {
throw new IOException("Can't load the schema", 0, $this->extractErrorMessage());
}
libxml_use_internal_errors(false);
$xml->documentURI = $file;

return $this->readNode($xml->documentElement, $file);
}

/**
* @throws IOException
*/
public function readFile(string $file): Schema
{
$xml = $this->getDOM($file);
Expand All @@ -1272,9 +1286,12 @@ public function readFile(string $file): Schema
private function getDOM(string $file): DOMDocument
{
$xml = new DOMDocument('1.0', 'UTF-8');
if (!$xml->load($file)) {
throw new IOException("Can't load the file $file");
libxml_use_internal_errors(true);
if (!@$xml->load($file)) {
libxml_use_internal_errors(false);
throw new IOException("Can't load the file '$file'", 0, $this->extractErrorMessage());
}
libxml_use_internal_errors(false);

return $xml;
}
Expand Down Expand Up @@ -1382,10 +1399,20 @@ private function setLoadedFile(string $key, Schema $schema): void
$this->loadedFiles[$key] = $schema;
}

private function setLoadedSchema(DOMElement $node, Schema $schema): void
private function setLoadedSchemaFromElement(DOMElement $node, Schema $schema): void
{
if ($node->hasAttribute('targetNamespace')) {
$this->loadedSchemas[$node->getAttribute('targetNamespace')][] = $schema;
$this->setLoadedSchema($node->getAttribute('targetNamespace'), $schema);
}
}

private function setLoadedSchema(string $namespace, Schema $schema): void
{
if (!isset($this->loadedSchemas[$namespace])) {
$this->loadedSchemas[$namespace] = array();
}
if (!in_array($schema, $this->loadedSchemas[$namespace], true)) {
$this->loadedSchemas[$namespace][] = $schema;
}
}

Expand Down

0 comments on commit 0a14320

Please sign in to comment.