diff --git a/README.md b/README.md index 1588f6a1..143e8bd6 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,8 @@ Here is an explanation on the meaning of each parameter: * `xsd2php.known_locations` (optional) override remote location with a local file. +* `xsd2php.strict_types` (optional) enable strict types for setter arguments. + * `xsd2php.known_namespace_locations` (optional) Specify schema location by namespace. This can be used to read schemas which import namespaces but do not specify schemaLocation attributes. diff --git a/composer.json b/composer.json index 0755d446..78ae53fd 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "authors": [ { "name": "Asmir Mustafic", - "email" : "goetas@gmail.com" + "email": "goetas@gmail.com" } ], "keywords": [ @@ -18,21 +18,21 @@ ], "license": "MIT", "require": { - "php": ">=7.2|^8.0", - "symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0|^7.0", - "symfony/dependency-injection": "^2.2|^3.0|^4.0|^5.0|^6.0|^7.0", - "symfony/yaml": "^2.2|^3.0|^4.0|^5.0|^6.0|^7.0", - "symfony/config": "^2.2|^3.0|^4.0|^5.0|^6.0|^7.0", + "php": "^8.0", + "symfony/console": "^6.0|^7.0", + "symfony/dependency-injection": "^6.0|^7.0", + "symfony/yaml": "^6.0|^7.0", + "symfony/config": "^6.0|^7.0", "goetas-webservices/xsd-reader": "^0.3.7 | ^0.4.1", "doctrine/inflector": "^2.0", - "laminas/laminas-code": "^3.3.2|^4.0", + "laminas/laminas-code": "^4.0", "psr/log": "^1.0 | ^2.0 | ^3.0" }, "require-dev": { "phpunit/phpunit": "^6.0|^7.0|^8.0|^9.0", "jms/serializer": "^1.9|^2.0|^3.0", "goetas-webservices/xsd2php-runtime": "^0.2.13@dev", - "symfony/validator": "^2.3.24|^3.0|^4.0|^5.0|^6.0|^7.0", + "symfony/validator": "^6.0|^7.0", "dms/phpunit-arraysubset-asserts": "^0.3.1" }, "autoload": { diff --git a/src/AbstractConverter.php b/src/AbstractConverter.php index aec6e13a..b2b01d02 100644 --- a/src/AbstractConverter.php +++ b/src/AbstractConverter.php @@ -17,57 +17,21 @@ abstract class AbstractConverter { use LoggerAwareTrait; - protected $baseSchemas = [ + protected array $baseSchemas = [ 'http://www.w3.org/2001/XMLSchema', 'http://www.w3.org/XML/1998/namespace', ]; - protected $namespaces = [ + protected array $namespaces = [ 'http://www.w3.org/2001/XMLSchema' => '', 'http://www.w3.org/XML/1998/namespace' => '', ]; - /** - * @var \GoetasWebservices\Xsd\XsdToPhp\Naming\NamingStrategy - */ - private $namingStrategy; + private NamingStrategy $namingStrategy; - abstract public function convert(array $schemas); - - protected $typeAliases = []; - - protected $aliasCache = []; - - public function addAliasMap($ns, $name, callable $handler) - { - $this->logger->info("Added map $ns $name"); - $this->typeAliases[$ns][$name] = $handler; - } + protected array $typeAliases = []; - public function addAliasMapType($ns, $name, $type) - { - $this->addAliasMap($ns, $name, function () use ($type) { - return $type; - }); - } - - public function getTypeAliases(): array - { - return $this->typeAliases; - } - - public function getTypeAlias($type, ?Schema $schemapos = null) - { - $schema = $schemapos ?: $type->getSchema(); - - $cid = $schema->getTargetNamespace() . '|' . $type->getName(); - if (isset($this->aliasCache[$cid])) { - return $this->aliasCache[$cid]; - } - if (isset($this->typeAliases[$schema->getTargetNamespace()][$type->getName()])) { - return $this->aliasCache[$cid] = call_user_func($this->typeAliases[$schema->getTargetNamespace()][$type->getName()], $type); - } - } + protected array $aliasCache = []; public function __construct(NamingStrategy $namingStrategy, ?LoggerInterface $logger = null) { @@ -186,15 +150,48 @@ public function __construct(NamingStrategy $namingStrategy, ?LoggerInterface $lo }); } - /** - * @return \GoetasWebservices\Xsd\XsdToPhp\Naming\NamingStrategy - */ - protected function getNamingStrategy() + abstract public function convert(array $schemas); + + public function addAliasMap(string $ns, string $name, callable $handler): void + { + $this->logger->info("Added map $ns $name"); + $this->typeAliases[$ns][$name] = $handler; + } + + public function addAliasMapType(string $ns, string $name, $type): void + { + $this->addAliasMap($ns, $name, function () use ($type) { + return $type; + }); + } + + public function getTypeAliases(): array + { + return $this->typeAliases; + } + + public function getTypeAlias($type, Schema $schemapos = null) + { + $schema = $schemapos ?: $type->getSchema(); + + $cid = $schema->getTargetNamespace() . '|' . $type->getName(); + if (isset($this->aliasCache[$cid])) { + return $this->aliasCache[$cid]; + } + if (isset($this->typeAliases[$schema->getTargetNamespace()][$type->getName()])) { + return $this->aliasCache[$cid] = + call_user_func($this->typeAliases[$schema->getTargetNamespace()][$type->getName()], $type); + } + + return null; + } + + protected function getNamingStrategy(): NamingStrategy { return $this->namingStrategy; } - public function addNamespace($ns, $phpNamespace) + public function addNamespace(string $ns, string $phpNamespace): static { $this->logger->info("Added ns mapping $ns, $phpNamespace"); $this->namespaces[$ns] = $phpNamespace; @@ -202,15 +199,12 @@ public function addNamespace($ns, $phpNamespace) return $this; } - protected function cleanName($name) + protected function cleanName(string $name): string { return preg_replace('/<.*>/', '', $name); } - /** - * @return \GoetasWebservices\XML\XSDReader\Schema\Type\Type|null - */ - protected function isArrayType(Type $type) + protected function isArrayType(Type $type): ?Type { if ($type instanceof SimpleType) { if ($type->getList()) { @@ -227,31 +221,27 @@ protected function isArrayType(Type $type) return null; } - /** - * @return \GoetasWebservices\XML\XSDReader\Schema\Element\ElementSingle|null - */ - protected function isArrayNestedElement(Type $type) + protected function isArrayNestedElement(Type $type): ?ElementSingle { if ($type instanceof ComplexType && !$type->getParent() && !$type->getAttributes() && count($type->getElements()) === 1) { $elements = $type->getElements(); return $this->isArrayElement(reset($elements)); } + + return null; } - /** - * @param mixed $element - * - * @return \GoetasWebservices\XML\XSDReader\Schema\Element\ElementSingle|null - */ - protected function isArrayElement($element) + protected function isArrayElement(mixed $element): ?ElementSingle { if ($element instanceof ElementSingle && ($element->getMax() > 1 || $element->getMax() === -1)) { return $element; } + + return null; } - public function getNamespaces() + public function getNamespaces(): array { return $this->namespaces; } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 1ea6fe51..f425c27c 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -66,11 +66,11 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->end() ->arrayNode('aliases')->fixXmlConfig('alias') - ->prototype('array') - ->prototype('scalar') - ->end() + ->prototype('scalar') ->end() ->end() + ->booleanNode('strict_types') + ->end() ->end(); return $treeBuilder; diff --git a/src/DependencyInjection/Xsd2PhpExtension.php b/src/DependencyInjection/Xsd2PhpExtension.php index 7c818243..64cf9ac5 100644 --- a/src/DependencyInjection/Xsd2PhpExtension.php +++ b/src/DependencyInjection/Xsd2PhpExtension.php @@ -56,6 +56,11 @@ public function load(array $configs, ContainerBuilder $container) $converter->addMethodCall('setUseCdata', [$config['configs_jms']['xml_cdata']]); } + if ($config['strict_types'] ?? false) { + $container->getDefinition('goetas_webservices.xsd2php.php.class_generator') + ->addMethodCall('enableStrictTypes'); + } + $container->setParameter('goetas_webservices.xsd2php.config', $config); } diff --git a/src/Jms/YamlConverter.php b/src/Jms/YamlConverter.php index 98b5e2a3..86c5d01a 100644 --- a/src/Jms/YamlConverter.php +++ b/src/Jms/YamlConverter.php @@ -6,6 +6,7 @@ use Exception; use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeContainer; use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem; +use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeSingle; use GoetasWebservices\XML\XSDReader\Schema\Element\Element; use GoetasWebservices\XML\XSDReader\Schema\Element\ElementContainer; use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef; @@ -26,7 +27,7 @@ class YamlConverter extends AbstractConverter { - protected $useCdata = true; + protected bool $useCdata = true; public function __construct(NamingStrategy $namingStrategy) { @@ -47,7 +48,7 @@ public function __construct(NamingStrategy $namingStrategy) }); } - public function setUseCdata($value) + public function setUseCdata(bool $value): static { $this->logger->info("Set useCdata $value"); $this->useCdata = $value; @@ -57,7 +58,7 @@ public function setUseCdata($value) private $classes = []; - public function convert(array $schemas) + public function convert(array $schemas): array { $visited = []; $this->classes = []; @@ -68,7 +69,10 @@ public function convert(array $schemas) return $this->getTypes(); } - private function flattAttributes(AttributeContainer $container) + /** + * @return AttributeContainer[] + */ + private function flattAttributes(AttributeContainer $container): array { $items = []; foreach ($container->getAttributes() as $attr) { @@ -82,7 +86,10 @@ private function flattAttributes(AttributeContainer $container) return $items; } - private function flattElements(ElementContainer $container) + /** + * @return ElementContainer[] + */ + private function flattElements(ElementContainer $container): array { $items = []; foreach ($container->getElements() as $attr) { @@ -99,7 +106,7 @@ private function flattElements(ElementContainer $container) /** * @return PHPClass[] */ - public function getTypes() + public function getTypes(): array { uasort($this->classes, function ($a, $b) { return strcmp(key($a), key($b)); @@ -118,7 +125,10 @@ public function getTypes() return $ret; } - private function navigate(Schema $schema, array &$visited) + /** + * @param array $visited + */ + private function navigate(Schema $schema, array &$visited): void { if (isset($visited[spl_object_hash($schema)])) { return; @@ -139,7 +149,7 @@ private function navigate(Schema $schema, array &$visited) } } - private function visitTypeBase(&$class, &$data, Type $type, $name) + private function visitTypeBase(&$class, &$data, Type $type, $name): void { if ($type instanceof BaseComplexType) { $this->visitBaseComplexType($class, $data, $type, $name); @@ -152,7 +162,7 @@ private function visitTypeBase(&$class, &$data, Type $type, $name) } } - public function &visitElementDef(Schema $schema, ElementDef $element) + public function &visitElementDef(Schema $schema, ElementDef $element): array { if (!isset($this->classes[spl_object_hash($element)])) { $className = $this->findPHPNamespace($element) . '\\' . $this->getNamingStrategy()->getItemName($element); @@ -166,7 +176,8 @@ public function &visitElementDef(Schema $schema, ElementDef $element) $data['xml_root_namespace'] = $schema->getTargetNamespace(); if (!$schema->getElementsQualification() && !($element instanceof Element && $element->isQualified())) { - $data['xml_root_name'] = 'ns-' . substr(sha1($data['xml_root_namespace']), 0, 8) . ':' . $element->getName(); + $data['xml_root_name'] = 'ns-' . substr(sha1($data['xml_root_namespace']), 0, 8) + . ':' . $element->getName(); } } $this->classes[spl_object_hash($element)]['class'] = &$class; @@ -180,11 +191,14 @@ public function &visitElementDef(Schema $schema, ElementDef $element) $data['extends'] = $visitedTypeClass; - $this->classes[spl_object_hash($element)]['skip'] = in_array($element->getSchema()->getTargetNamespace(), $this->baseSchemas, true) - || $this->getTypeAlias($type, $type->getSchema()) - ; - - if (!$this->classes[spl_object_hash($element)]['skip'] && ($p = $this->getPropertyInHierarchy($visitedTypeClass, '__value'))) { + $this->classes[spl_object_hash($element)]['skip'] = + in_array($element->getSchema()->getTargetNamespace(), $this->baseSchemas, true) || + $this->getTypeAlias($type, $type->getSchema()); + + if ( + !$this->classes[spl_object_hash($element)]['skip'] && + ($p = $this->getPropertyInHierarchy($visitedTypeClass, '__value')) + ) { $data['properties']['__value'] = $p; } } @@ -192,7 +206,7 @@ public function &visitElementDef(Schema $schema, ElementDef $element) return $this->classes[spl_object_hash($element)]['class']; } - private function findPHPNamespace(SchemaItem $item) + private function findPHPNamespace(SchemaItem $item): string { $schema = $item->getSchema(); @@ -203,7 +217,7 @@ private function findPHPNamespace(SchemaItem $item) return $this->namespaces[$schema->getTargetNamespace()]; } - private function findPHPName(Type $type) + private function findPHPName(Type $type): string { $schema = $type->getSchema(); @@ -217,7 +231,10 @@ private function findPHPName(Type $type) return $ns . '\\' . $name; } - public function &visitType(Type $type, $force = false) + /** + * @return array + */ + public function &visitType(Type $type, bool $force = false): array { $skip = in_array($type->getSchema()->getTargetNamespace(), $this->baseSchemas, true); @@ -264,13 +281,7 @@ public function &visitType(Type $type, $force = false) return $this->classes[spl_object_hash($type)]['class']; } - /** - * @param string $parentName - * @param string $parentClass - * - * @return array - */ - private function &visitTypeAnonymous(Type $type, $parentName, $parentClass) + private function &visitTypeAnonymous(Type $type, $parentName, $parentClass): array { if (!isset($this->classes[spl_object_hash($type)])) { $class = []; @@ -290,18 +301,19 @@ private function &visitTypeAnonymous(Type $type, $parentName, $parentClass) return $this->classes[spl_object_hash($type)]['class']; } - private function visitComplexType(&$class, &$data, ComplexType $type) + private function visitComplexType(&$class, &$data, ComplexType $type): void { $schema = $type->getSchema(); if (!isset($data['properties'])) { $data['properties'] = []; } foreach ($this->flattElements($type) as $element) { - $data['properties'][$this->getNamingStrategy()->getPropertyName($element)] = $this->visitElement($class, $schema, $element); + $propName = $this->getNamingStrategy()->getPropertyName($element); + $data['properties'][$propName] = $this->visitElement($class, $schema, $element); } } - protected function visitSimpleType(&$class, &$data, SimpleType $type, $name) + protected function visitSimpleType(&$class, &$data, SimpleType $type, $name): void { if ($restriction = $type->getRestriction()) { $parent = $restriction->getBase(); @@ -316,7 +328,7 @@ protected function visitSimpleType(&$class, &$data, SimpleType $type, $name) } } - private function visitBaseComplexType(&$class, &$data, BaseComplexType $type, $name) + private function visitBaseComplexType(&$class, &$data, BaseComplexType $type, $name): void { $parent = $type->getParent(); if ($parent) { @@ -331,11 +343,12 @@ private function visitBaseComplexType(&$class, &$data, BaseComplexType $type, $n $data['properties'] = []; } foreach ($this->flattAttributes($type) as $attr) { - $data['properties'][$this->getNamingStrategy()->getPropertyName($attr)] = $this->visitAttribute($class, $schema, $attr); + $propName = $this->getNamingStrategy()->getPropertyName($attr); + $data['properties'][$propName] = $this->visitAttribute($class, $schema, $attr); } } - protected function &handleClassExtension(&$class, &$data, Type $type, $parentName) + protected function &handleClassExtension(array &$class, array &$data, Type $type, string $parentName): array { $property = []; if ($alias = $this->getTypeAlias($type)) { @@ -372,7 +385,7 @@ protected function &handleClassExtension(&$class, &$data, Type $type, $parentNam return $property; } - protected function &visitAttribute(&$class, Schema $schema, AttributeItem $attribute) + protected function &visitAttribute(array &$class, Schema $schema, AttributeItem $attribute): array { $property = []; $property['expose'] = true; @@ -380,18 +393,22 @@ protected function &visitAttribute(&$class, Schema $schema, AttributeItem $attri $property['serialized_name'] = $attribute->getName(); $inflector = InflectorFactory::create()->build(); - $property['accessor']['getter'] = 'get' . $inflector->classify($this->getNamingStrategy()->getPropertyName($attribute)); - $property['accessor']['setter'] = 'set' . $inflector->classify($this->getNamingStrategy()->getPropertyName($attribute)); + $property['accessor']['getter'] = + 'get' . $inflector->classify($this->getNamingStrategy()->getPropertyName($attribute)); + $property['accessor']['setter'] = + 'set' . $inflector->classify($this->getNamingStrategy()->getPropertyName($attribute)); $property['xml_attribute'] = true; + /** @var AttributeSingle $attribute*/ if ($alias = $this->getTypeAlias($attribute)) { $property['type'] = $alias; } elseif ($itemOfArray = $this->isArrayType($attribute->getType())) { if ($valueProp = $this->typeHasValue($itemOfArray, $class, 'xx')) { $property['type'] = "GoetasWebservices\Xsd\XsdToPhp\Jms\SimpleListOf<" . $valueProp . '>'; } else { - $property['type'] = "GoetasWebservices\Xsd\XsdToPhp\Jms\SimpleListOf<" . $this->findPHPName($itemOfArray) . '>'; + $property['type'] = "GoetasWebservices\Xsd\XsdToPhp\Jms\SimpleListOf<" + . $this->findPHPName($itemOfArray) . '>'; } } else { $property['type'] = $this->findPHPClass($class, $attribute); @@ -400,7 +417,7 @@ protected function &visitAttribute(&$class, Schema $schema, AttributeItem $attri return $property; } - protected function typeHasValue(Type $type, $parentClass, $name) + protected function typeHasValue(Type $type, array $parentClass, $name): string|false { $newType = null; do { @@ -430,21 +447,28 @@ protected function typeHasValue(Type $type, $parentClass, $name) return $prop['type']; } } while ( - (method_exists($type, 'getRestriction') && $type->getRestriction() && ($newType = $type->getRestriction()->getBase())) - || - (method_exists($type, 'getExtension') && $type->getExtension() && ($newType = $type->getExtension()->getBase())) + ( + method_exists($type, 'getRestriction') && + $type->getRestriction() && + ($newType = $type->getRestriction()->getBase()) + ) || ( + method_exists($type, 'getExtension') && + $type->getExtension() && + ($newType = $type->getExtension()->getBase()) + ) ); return false; } - public function getPropertyInHierarchy($class, $prop) + public function getPropertyInHierarchy(array $class, string $prop): array|false { $props = reset($class); if ( (isset($props['properties']) && count($props['properties']) > 0 && !isset($props['properties'][$prop])) || - (isset($props['properties']) && count($props['properties']) > 1)) { + (isset($props['properties']) && count($props['properties']) > 1) + ) { return false; } @@ -459,15 +483,15 @@ public function getPropertyInHierarchy($class, $prop) return false; } - /** - * @param Element|ElementSingle $element - * - * @return string|null - */ - protected function getElementNamespace(Schema $schema, ElementItem $element) + protected function getElementNamespace(Schema $schema, ElementItem $element): ?string { - if ($element->getSchema()->getTargetNamespace() && - ($schema->getElementsQualification() || ($element instanceof Element && $element->isQualified()) || !$element->isLocal()) + if ( + $element->getSchema()->getTargetNamespace() && + ( + $schema->getElementsQualification() || + ($element instanceof Element && $element->isQualified()) || + ($element instanceof ElementSingle && !$element->isLocal()) + ) ) { return $element->getSchema()->getTargetNamespace(); } @@ -475,14 +499,7 @@ protected function getElementNamespace(Schema $schema, ElementItem $element) return null; } - /** - * @param PHPClass $class - * @param Element $element - * @param bool $arrayize - * - * @return array - */ - protected function &visitElement(&$class, Schema $schema, ElementItem $element, $arrayize = true) + protected function &visitElement(array &$class, Schema $schema, ElementItem $element, bool $arrayize = true): array { $property = []; $property['expose'] = true; @@ -492,14 +509,22 @@ protected function &visitElement(&$class, Schema $schema, ElementItem $element, if (!$this->useCdata) { $property['xml_element']['cdata'] = $this->useCdata; } + + $inflector = InflectorFactory::create()->build(); + $property['accessor']['getter'] = 'get' . + $inflector->classify($this->getNamingStrategy()->getPropertyName($element)); + $property['accessor']['setter'] = 'set' . + $inflector->classify($this->getNamingStrategy()->getPropertyName($element)); + + if (!$element instanceof ElementSingle) { + return $property; + } + $elementNamespace = $this->getElementNamespace($schema, $element); - if ($elementNamespace) { + if ($elementNamespace && $element->isQualified()) { $property['xml_element']['namespace'] = $elementNamespace; } - $inflector = InflectorFactory::create()->build(); - $property['accessor']['getter'] = 'get' . $inflector->classify($this->getNamingStrategy()->getPropertyName($element)); - $property['accessor']['setter'] = 'set' . $inflector->classify($this->getNamingStrategy()->getPropertyName($element)); $t = $element->getType(); if ($arrayize) { @@ -576,7 +601,7 @@ protected function &visitElement(&$class, Schema $schema, ElementItem $element, return $property; } - protected function findPHPClass(&$class, Item $node) + protected function findPHPClass(array &$class, Item $node): string|null { $type = $node->getType(); @@ -602,7 +627,7 @@ protected function findPHPClass(&$class, Item $node) return key($visited); } - private function findPHPElementClassName(&$class, ElementItem $element): string + private function findPHPElementClassName(array &$class, ElementItem $element): string { if ($element instanceof ElementRef) { $elRefClass = $this->visitElementDef($element->getSchema(), $element->getReferencedElement()); diff --git a/src/Jms/YamlValidatorConverter.php b/src/Jms/YamlValidatorConverter.php index 0847a789..0fd48959 100644 --- a/src/Jms/YamlValidatorConverter.php +++ b/src/Jms/YamlValidatorConverter.php @@ -4,7 +4,6 @@ use GoetasWebservices\XML\XSDReader\Schema\Attribute\Attribute; use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem; -use GoetasWebservices\XML\XSDReader\Schema\Element\Element; use GoetasWebservices\XML\XSDReader\Schema\Element\ElementItem; use GoetasWebservices\XML\XSDReader\Schema\Schema; use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType; @@ -20,7 +19,7 @@ class YamlValidatorConverter extends YamlConverter * * @return PHPClass[] */ - public function getTypes() + public function getTypes(): array { $classes = parent::getTypes(); @@ -153,7 +152,7 @@ private function loadValidatorType(array &$property, Type $type, $arrayized = fa '\p{IsLatin-1Supplement}' => '\x{0080}-\x{00FF}', ]; foreach ($unicodeClasses as $from => $to) { - if (preg_match('~\[.*'.preg_quote($from, '~').'.*\]~', $regexPattern)) { + if (preg_match('~\[.*' . preg_quote($from, '~') . '.*\]~', $regexPattern)) { $regexPattern = str_replace($from, $to, $regexPattern); } else { $regexPattern = str_replace($from, "[$to]", $regexPattern); @@ -212,12 +211,15 @@ private function loadValidatorType(array &$property, Type $type, $arrayized = fa private function loadValidatorElement(array &$property, ElementItem $element) { /* @var $element Element */ - $type = $element->getType(); + $type = null; + if (method_exists($element, 'getType')) { + $type = $element->getType(); + } $attrs = []; - $arrayized = strpos($property['type'], 'array<') === 0; + $arrayized = strpos($property['type'] ?? '', 'array<') === 0; - if ($arrayized) { + if ($arrayized && $type) { if ($itemOfArray = $this->isArrayNestedElement($type)) { $attrs = [ 'min' => min($element->getMin(), $itemOfArray->getMin()), @@ -243,7 +245,11 @@ private function loadValidatorElement(array &$property, ElementItem $element) unset($attrs['max']); } - $rules = $this->loadValidatorType($property, $type, $arrayized); + if ($type) { + $rules = $this->loadValidatorType($property, $type, $arrayized); + } else { + $rules = []; + } if ($element->getMin() > 0) { $property['validation'][] = [ @@ -299,7 +305,7 @@ private function loadValidatorAttribute(array &$property, AttributeItem $attribu * @param array $data * @param string $name */ - protected function visitSimpleType(&$class, &$data, SimpleType $type, $name) + protected function visitSimpleType(&$class, &$data, SimpleType $type, $name): void { parent::visitSimpleType($class, $data, $type, $name); @@ -322,7 +328,7 @@ protected function visitSimpleType(&$class, &$data, SimpleType $type, $name) * * @return PHPProperty */ - protected function &visitElement(&$class, Schema $schema, ElementItem $element, $arrayize = true) + protected function &visitElement(array &$class, Schema $schema, ElementItem $element, bool $arrayize = true): array { $property = parent::visitElement($class, $schema, $element, $arrayize); @@ -338,7 +344,7 @@ protected function &visitElement(&$class, Schema $schema, ElementItem $element, * * @return array */ - protected function &visitAttribute(&$class, Schema $schema, AttributeItem $attribute) + protected function &visitAttribute(array &$class, Schema $schema, AttributeItem $attribute): array { $property = parent::visitAttribute($class, $schema, $attribute); @@ -354,7 +360,7 @@ protected function &visitAttribute(&$class, Schema $schema, AttributeItem $attri * @param array $data * @param string $parentName */ - protected function &handleClassExtension(&$class, &$data, Type $type, $parentName) + protected function &handleClassExtension(array &$class, array &$data, Type $type, string $parentName): array { $property = parent::handleClassExtension($class, $data, $type, $parentName); diff --git a/src/Php/ClassGenerator.php b/src/Php/ClassGenerator.php index ce726a75..43671413 100644 --- a/src/Php/ClassGenerator.php +++ b/src/Php/ClassGenerator.php @@ -2,11 +2,13 @@ namespace GoetasWebservices\Xsd\XsdToPhp\Php; +use Doctrine\Inflector\Inflector; use Doctrine\Inflector\InflectorFactory; use GoetasWebservices\Xsd\XsdToPhp\Php\Structure\PHPClass; use GoetasWebservices\Xsd\XsdToPhp\Php\Structure\PHPClassOf; use GoetasWebservices\Xsd\XsdToPhp\Php\Structure\PHPProperty; use Laminas\Code\Generator; +use Laminas\Code\Generator\ClassGenerator as LaminasClassGenerator; use Laminas\Code\Generator\DocBlock\Tag\ParamTag; use Laminas\Code\Generator\DocBlock\Tag\ReturnTag; use Laminas\Code\Generator\DocBlock\Tag\VarTag; @@ -18,23 +20,42 @@ class ClassGenerator { - private $strictTypes; + private bool $strictTypes = false; - public function __construct(bool $strictTypes = false) + protected Inflector $inflector; + + public function __construct() { - $this->strictTypes = $strictTypes; + $this->inflector = InflectorFactory::create()->build(); } - private function handleBody(Generator\ClassGenerator $class, PHPClass $type) + public function enableStrictTypes(): void + { + $this->strictTypes = true; + } + + private function handleBody(Generator\ClassGenerator $class, PHPClass $type): bool { foreach ($type->getProperties() as $prop) { - if ($prop->getName() !== '__value') { - $this->handleProperty($class, $prop); - } - } - foreach ($type->getProperties() as $prop) { - if ($prop->getName() !== '__value') { - $this->handleMethod($class, $prop, $type); + $name = $prop->getName(); + if ($name !== '__value') { + $parentProp = $type->getPropertyInHierarchy($name, true); + $fixed = $prop->getFixed(); + $valDiff = $parentProp && + (($fixed ?? $prop->getDefault()) !== ($parentProp->getFixed() ?? $parentProp->getDefault())); + + if (!$parentProp || $valDiff) { + $this->handleProperty($class, $prop); + } + + if (!$parentProp) { + $this->handleGetter($class, $prop, $type); + $this->handleSetter($class, $prop, $type); + + if ($prop->getType() instanceof PHPClassOf) { + $this->handleAdder($class, $prop, $type); + } + } } } @@ -45,8 +66,12 @@ private function handleBody(Generator\ClassGenerator $class, PHPClass $type) return true; } - private function handleValueMethod(Generator\ClassGenerator $generator, PHPProperty $prop, PHPClass $class, $all = true) - { + private function handleValueMethod( + Generator\ClassGenerator $generator, + PHPProperty $prop, + PHPClass $class, + bool $all = true + ): void { $type = $prop->getType(); $docblock = new DocBlockGenerator('Construct'); @@ -113,37 +138,37 @@ private function handleValueMethod(Generator\ClassGenerator $generator, PHPPrope $generator->addMethodFromGenerator($method); } - private function handleSetter(Generator\ClassGenerator $generator, PHPProperty $prop, PHPClass $class) + private function handleSetter(Generator\ClassGenerator $generator, PHPProperty $prop, PHPClass $class): void { + $name = $prop->getName(); $methodBody = ''; $docblock = new DocBlockGenerator(); $docblock->setWordWrap(false); - - $docblock->setShortDescription('Sets a new ' . $prop->getName()); + $docblock->setShortDescription('Sets a new ' . $name); if ($prop->getDoc()) { $docblock->setLongDescription($prop->getDoc()); } - $patramTag = new ParamTag($prop->getName()); + $patramTag = new ParamTag($name); $docblock->setTag($patramTag); - $return = new ReturnTag('self'); + $return = new ReturnTag('static'); $docblock->setTag($return); $type = $prop->getType(); - $inflector = InflectorFactory::create()->build(); - $method = new MethodGenerator('set' . $inflector->classify($prop->getName())); + $method = new MethodGenerator('set' . $this->inflector->classify($name)); - $parameter = new ParameterGenerator($prop->getName()); + $parameter = new ParameterGenerator($name); if ($type && $type instanceof PHPClassOf) { $patramTag->setTypes($type->getArg() ->getType()->getPhpType() . '[]'); $parameter->setType('array'); - if ($p = $type->getArg()->getType()->isSimpleType() + if ( + $p = $type->getArg()->getType()->isSimpleType() ) { if (($t = $p->getType())) { $patramTag->setTypes($t->getPhpType()); @@ -179,14 +204,15 @@ private function handleSetter(Generator\ClassGenerator $generator, PHPProperty $ $parameter->setDefaultValue(null); } - if (($parameter->getDefaultValue() instanceof ValueGenerator) && + if ( + ($parameter->getDefaultValue() instanceof ValueGenerator) && $parameter->getDefaultValue()->getValue() === null && $parameter->getType() !== null && - substr($parameter->getType(), 0, 1) !== '?') { + substr($parameter->getType(), 0, 1) !== '?' + ) { $parameter->setType('?' . $parameter->getType()); } - $methodBody .= '$this->' . $prop->getName() . ' = $' . $prop->getName() . ';' . PHP_EOL; - $methodBody .= 'return $this;'; + $methodBody .= '$this->' . $name . ' = $' . $name . ';' . PHP_EOL . 'return $this;'; $method->setBody($methodBody); $method->setDocBlock($docblock); $method->setParameter($parameter); @@ -194,14 +220,14 @@ private function handleSetter(Generator\ClassGenerator $generator, PHPProperty $ $generator->addMethodFromGenerator($method); } - private function handleGetter(Generator\ClassGenerator $generator, PHPProperty $prop, PHPClass $class) + private function handleGetter(Generator\ClassGenerator $generator, PHPProperty $prop, PHPClass $class): void { - $inflector = InflectorFactory::create()->build(); + $name = $prop->getName(); if ($prop->getType() instanceof PHPClassOf) { $docblock = new DocBlockGenerator(); $docblock->setWordWrap(false); - $docblock->setShortDescription('isset ' . $prop->getName()); + $docblock->setShortDescription("isset $name"); if ($prop->getDoc()) { $docblock->setLongDescription($prop->getDoc()); } @@ -214,14 +240,14 @@ private function handleGetter(Generator\ClassGenerator $generator, PHPProperty $ $paramIndex = new ParameterGenerator('index'); - $method = new MethodGenerator('isset' . $inflector->classify($prop->getName()), [$paramIndex]); + $method = new MethodGenerator('isset' . $this->inflector->classify($name), [$paramIndex]); $method->setDocBlock($docblock); - $method->setBody('return isset($this->' . $prop->getName() . '[$index]);'); + $method->setBody('return isset($this->' . $name . '[$index]);'); $generator->addMethodFromGenerator($method); $docblock = new DocBlockGenerator(); $docblock->setWordWrap(false); - $docblock->setShortDescription('unset ' . $prop->getName()); + $docblock->setShortDescription("unset $name"); if ($prop->getDoc()) { $docblock->setLongDescription($prop->getDoc()); } @@ -232,17 +258,17 @@ private function handleGetter(Generator\ClassGenerator $generator, PHPProperty $ $docblock->setTag(new ReturnTag('void')); - $method = new MethodGenerator('unset' . $inflector->classify($prop->getName()), [$paramIndex]); + $method = new MethodGenerator('unset' . $this->inflector->classify($name), [$paramIndex]); $method->setDocBlock($docblock); - $method->setBody('unset($this->' . $prop->getName() . '[$index]);'); + $method->setBody('unset($this->' . $name . '[$index]);'); + $generator->addMethodFromGenerator($method); } - // //// $docblock = new DocBlockGenerator(); $docblock->setWordWrap(false); - $docblock->setShortDescription('Gets as ' . $prop->getName()); + $docblock->setShortDescription("Gets as $name"); if ($prop->getDoc()) { $docblock->setLongDescription($prop->getDoc()); @@ -269,16 +295,16 @@ private function handleGetter(Generator\ClassGenerator $generator, PHPProperty $ } $docblock->setTag($tag); - - $method = new MethodGenerator('get' . $inflector->classify($prop->getName())); + $method = new MethodGenerator('get' . $this->inflector->classify($name)); $method->setDocBlock($docblock); - $method->setBody('return $this->' . $prop->getName() . ';'); + $method->setBody('return $this->' . $name . ';'); $generator->addMethodFromGenerator($method); } - private function handleAdder(Generator\ClassGenerator $generator, PHPProperty $prop, PHPClass $class) + private function handleAdder(Generator\ClassGenerator $generator, PHPProperty $prop, PHPClass $class): void { + /** @var PHPClassOf $type */ $type = $prop->getType(); $propName = $type->getArg()->getName(); @@ -291,14 +317,13 @@ private function handleAdder(Generator\ClassGenerator $generator, PHPProperty $p } $return = new ReturnTag(); - $return->setTypes('self'); + $return->setTypes('static'); $docblock->setTag($return); $patramTag = new ParamTag($propName, $type->getArg()->getType()->getPhpType()); $docblock->setTag($patramTag); - $inflector = InflectorFactory::create()->build(); - $method = new MethodGenerator('addTo' . $inflector->classify($prop->getName())); + $method = new MethodGenerator('addTo' . $this->inflector->classify($prop->getName())); $parameter = new ParameterGenerator($propName); $tt = $type->getArg()->getType(); @@ -326,26 +351,30 @@ private function handleAdder(Generator\ClassGenerator $generator, PHPProperty $p $generator->addMethodFromGenerator($method); } - private function handleMethod(Generator\ClassGenerator $generator, PHPProperty $prop, PHPClass $class) + private function handleMethod(Generator\ClassGenerator $generator, PHPProperty $prop, PHPClass $class): void { if ($prop->getType() instanceof PHPClassOf) { $this->handleAdder($generator, $prop, $class); } $this->handleGetter($generator, $prop, $class); - $this->handleSetter($generator, $prop, $class); + + if ($prop->getFixed()) { + $this->handleSetter($generator, $prop, $class); + } } - private function handleProperty(Generator\ClassGenerator $class, PHPProperty $prop) + private function handleProperty(Generator\ClassGenerator $class, PHPProperty $prop): void { $generatedProp = new PropertyGenerator($prop->getName()); - $generatedProp->setVisibility(PropertyGenerator::VISIBILITY_PRIVATE); + $generatedProp->setVisibility($prop->getVisibility()); $class->addPropertyFromGenerator($generatedProp); - if ($prop->getType() && (!$prop->getType()->getNamespace() && $prop->getType()->getName() == 'array')) { - // $generatedProp->setDefaultValue(array(), PropertyValueGenerator::TYPE_AUTO, PropertyValueGenerator::OUTPUT_SINGLE_LINE); - } + /* if ($prop->getType() && (!$prop->getType()->getNamespace() && $prop->getType()->getName() == 'array')) { + $generatedProp + ->setDefaultValue([], PropertyValueGenerator::TYPE_AUTO, PropertyValueGenerator::OUTPUT_SINGLE_LINE); + } */ $docBlock = new DocBlockGenerator(); $docBlock->setWordWrap(false); @@ -366,6 +395,7 @@ private function handleProperty(Generator\ClassGenerator $class, PHPProperty $pr $tag->setTypes($t->getPhpType() . '[]'); } } + $generatedProp->setDefaultValue($type->getArg()->getDefault()); } elseif ($type) { if ($type->isNativeType()) { @@ -375,13 +405,22 @@ private function handleProperty(Generator\ClassGenerator $class, PHPProperty $pr } else { $tag->setTypes($prop->getType()->getPhpType()); } + + $value = $prop->getFixed() ?? $prop->getDefault(); + if ($value !== null) { + if ($type->getName() === 'bool') { + $value = $value === 'true'; + } + $generatedProp->setDefaultValue($value); + } } + $docBlock->setTag($tag); } - public function generate(PHPClass $type) + public function generate(PHPClass $type): ?LaminasClassGenerator { - $class = new \Laminas\Code\Generator\ClassGenerator(); + $class = new LaminasClassGenerator(); $docblock = new DocBlockGenerator('Class representing ' . $type->getName()); $docblock->setWordWrap(false); if ($type->getDoc()) { @@ -389,7 +428,7 @@ public function generate(PHPClass $type) } $class->setNamespaceName($type->getNamespace() ?: null); $class->setName($type->getName()); - $class->setDocblock($docblock); + $class->setDocBlock($docblock); $class->setImplementedInterfaces($type->getImplements()); if ($extends = $type->getExtends()) { @@ -412,5 +451,7 @@ public function generate(PHPClass $type) if ($this->handleBody($class, $type)) { return $class; } + + return null; } } diff --git a/src/Php/PhpConverter.php b/src/Php/PhpConverter.php index a8af6f56..8b539b29 100644 --- a/src/Php/PhpConverter.php +++ b/src/Php/PhpConverter.php @@ -3,7 +3,7 @@ namespace GoetasWebservices\Xsd\XsdToPhp\Php; use Exception; -use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem; +use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeSingle; use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup; use GoetasWebservices\XML\XSDReader\Schema\Element\Element; use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef; @@ -12,6 +12,9 @@ use GoetasWebservices\XML\XSDReader\Schema\Element\ElementSingle; use GoetasWebservices\XML\XSDReader\Schema\Element\Group; use GoetasWebservices\XML\XSDReader\Schema\Element\Choice; +use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef; +use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetFixed; +use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetMinMax; use GoetasWebservices\XML\XSDReader\Schema\Element\Sequence; use GoetasWebservices\XML\XSDReader\Schema\Item; use GoetasWebservices\XML\XSDReader\Schema\Schema; @@ -29,6 +32,10 @@ class PhpConverter extends AbstractConverter { + private array $classes = []; + + private array $skipByType = []; + public function __construct(NamingStrategy $namingStrategy, ?LoggerInterface $loggerInterface = null) { parent::__construct($namingStrategy, $loggerInterface); @@ -53,8 +60,6 @@ public function __construct(NamingStrategy $namingStrategy, ?LoggerInterface $lo }); } - private $classes = []; - public function convert(array $schemas): array { $visited = []; @@ -89,6 +94,7 @@ private function navigate(Schema $schema, array &$visited): void if (isset($visited[spl_object_hash($schema)])) { return; } + $visited[spl_object_hash($schema)] = true; foreach ($schema->getTypes() as $type) { @@ -122,10 +128,6 @@ private function visitTypeBase(PHPClass $class, Type $type): void /** * Process xsd:complexType xsd:sequence xsd:element - * - * @param PHPClass $class - * @param Schema $schema - * @param Sequence $sequence */ private function visitSequence(PHPClass $class, Schema $schema, Sequence $sequence): void { @@ -143,17 +145,22 @@ private function visitSequence(PHPClass $class, Schema $schema, Sequence $sequen /** * Process xsd:complexType xsd:choice xsd:element - * - * @param PHPClass $class - * @param Schema $schema - * @param Choice $choice */ - private function visitChoice(PHPClass $class, Schema $schema, Choice $choice): void + private function visitChoice(PHPClass $class, Schema $schema, Choice $choice, ?GroupRef $groupRef = null): void { foreach ($choice->getElements() as $choiceOption) { if ($choiceOption instanceof Sequence) { $this->visitSequence($class, $schema, $choiceOption); + } elseif ($choiceOption instanceof Choice) { + $this->visitChoice($class, $schema, $choiceOption); + } elseif ($choiceOption instanceof Group) { + $this->visitGroup($class, $schema, $choiceOption); } else { + /** @var Element $choiceOption */ + if ($groupRef !== null) { + $choiceOption->setMax($groupRef->getMax()); + $choiceOption->setMin($groupRef->getMin()); + } $property = $this->visitElement($class, $schema, $choiceOption); $class->addProperty($property); } @@ -165,6 +172,12 @@ private function visitGroup(PHPClass $class, Schema $schema, Group $group): void foreach ($group->getElements() as $childGroup) { if ($childGroup instanceof Group) { $this->visitGroup($class, $schema, $childGroup); + } elseif ($childGroup instanceof Choice) { + $childGroupRef = null; + if ($group instanceof GroupRef) { + $childGroupRef = $group; + } + $this->visitChoice($class, $schema, $childGroup, $childGroupRef); } else { $property = $this->visitElement($class, $schema, $childGroup); $class->addProperty($property); @@ -184,14 +197,7 @@ private function visitAttributeGroup(PHPClass $class, Schema $schema, AttributeG } } - private $skipByType = []; - - /** - * @param bool $skip - * - * @return PHPClass - */ - public function visitElementDef(ElementDef $element) + public function visitElementDef(ElementDef $element): PHPClass { if (!isset($this->classes[spl_object_hash($element)])) { $schema = $element->getSchema(); @@ -202,7 +208,10 @@ public function visitElementDef(ElementDef $element) $class->setDoc($element->getDoc()); if (!isset($this->namespaces[$schema->getTargetNamespace()])) { - throw new Exception(sprintf("Can't find a PHP namespace to '%s' namespace", $schema->getTargetNamespace())); + throw new Exception(sprintf( + "Can't find a PHP namespace to '%s' namespace", + $schema->getTargetNamespace() + )); } $class->setNamespace($this->namespaces[$schema->getTargetNamespace()]); @@ -230,7 +239,7 @@ public function isSkip($class): bool return !empty($this->skipByType[spl_object_hash($class)]); } - private function findPHPName(Type $type) + private function findPHPName(Type $type): array { $schema = $type->getSchema(); @@ -262,14 +271,9 @@ private function findPHPName(Type $type) } /** - * @param bool $force - * @param bool $skip - * - * @return PHPClass - * * @throws Exception */ - public function visitType(Type $type, $force = false) + public function visitType(Type $type, bool $force = false): PHPClass { if (!isset($this->classes[spl_object_hash($type)])) { $skip = in_array($type->getSchema()->getTargetNamespace(), $this->baseSchemas, true); @@ -300,7 +304,6 @@ public function visitType(Type $type, $force = false) } if (($this->isArrayType($type) || $this->isArrayNestedElement($type)) && !$force) { - $this->classes[spl_object_hash($type)]['skip'] = true; $this->skipByType[spl_object_hash($class)] = true; @@ -310,19 +313,15 @@ public function visitType(Type $type, $force = false) $this->classes[spl_object_hash($type)]['skip'] = $skip || (bool)$this->getTypeAlias($type); } elseif ($force) { if (!($type instanceof SimpleType) && !$this->getTypeAlias($type)) { - $this->classes[spl_object_hash($type)]['skip'] = in_array($type->getSchema()->getTargetNamespace(), $this->baseSchemas, true); + $this->classes[spl_object_hash($type)]['skip'] = + in_array($type->getSchema()->getTargetNamespace(), $this->baseSchemas, true); } } return $this->classes[spl_object_hash($type)]['class']; } - /** - * @param string $name - * - * @return PHPClass - */ - private function visitTypeAnonymous(Type $type, $name, PHPClass $parentClass) + private function visitTypeAnonymous(Type $type, string $name, PHPClass $parentClass): PHPClass { if (!isset($this->classes[spl_object_hash($type)])) { $this->classes[spl_object_hash($type)]['class'] = $class = new PHPClass(); @@ -424,8 +423,12 @@ private function visitBaseComplexType(PHPClass $class, BaseComplexType $type): v } } - private function visitAttribute(PHPClass $class, Schema $schema, AttributeItem $attribute, $arrayize = true) - { + private function visitAttribute( + PHPClass $class, + Schema $schema, + AttributeSingle $attribute, + bool $arrayize = true + ): PHPProperty { $property = new PHPProperty(); $property->setName($this->getNamingStrategy()->getPropertyName($attribute)); @@ -443,31 +446,38 @@ private function visitAttribute(PHPClass $class, Schema $schema, AttributeItem $ } $property->setDoc($attribute->getDoc()); + if ($attribute instanceof AttributeSingle) { + $property->setFixed($attribute->getFixed()); + } return $property; } - /** - * @param Element $element - * @param bool $arrayize - * - * @return PHPProperty - */ - private function visitElement(PHPClass $class, Schema $schema, ElementSingle $element, $arrayize = true) - { + private function visitElement( + PHPClass $class, + Schema $schema, + ElementItem|ElementSingle $element, + bool $arrayize = true + ): PHPProperty { $property = new PHPProperty(); $property->setName($this->getNamingStrategy()->getPropertyName($element)); $property->setDoc($element->getDoc()); - if ($element->isNil() || $element->getMin() === 0) { + + if ( + ($element instanceof ElementSingle && $element->isNil()) || + ($element instanceof InterfaceSetMinMax && $element->getMin() === 0) + ) { $property->setNullable(true); } + if (!$element instanceof ElementSingle) { + return $property; + } + $t = $element->getType(); if ($arrayize) { - if ($itemOfArray = $this->isArrayType($t)) { - if (!$itemOfArray->getName()) { if ($element instanceof ElementRef) { $refClass = $this->visitElementDef($element->getReferencedElement()); @@ -489,7 +499,6 @@ private function visitElement(PHPClass $class, Schema $schema, ElementSingle $el } if ($itemOfArray = $this->isArrayNestedElement($t)) { - if (!$t->getName()) { if ($element instanceof ElementRef) { $refClass = $this->visitElementDef($element->getReferencedElement()); @@ -520,11 +529,14 @@ private function visitElement(PHPClass $class, Schema $schema, ElementSingle $el } $property->setType($this->findPHPElementClassName($class, $element)); + if ($element instanceof InterfaceSetFixed) { + $property->setFixed($element->getFixed()); + } return $property; } - private function findPHPClass(PHPClass $class, Item $node, $force = false) + private function findPHPClass(PHPClass $class, Item $node, bool $force = false): PHPClass { if ($node instanceof ElementRef) { return $this->visitElementDef($node->getReferencedElement()); @@ -539,7 +551,7 @@ private function findPHPClass(PHPClass $class, Item $node, $force = false) return $this->visitType($node->getType(), $force); } - private function typeHasValue(Type $type, PHPClass $parentClass, $name) + private function typeHasValue(Type $type, PHPClass $parentClass, string $name): PHPClass|false { $newType = null; do { @@ -573,13 +585,14 @@ private function typeHasValue(Type $type, PHPClass $parentClass, $name) return false; } - private function findPHPElementClassName(PHPClass $class, ElementItem $element) + private function findPHPElementClassName(PHPClass $class, ElementItem $element): PHPClass { if ($element instanceof ElementRef) { - $elRefClass = $this->visitElementDef($element->getReferencedElement()); - $refType = $this->findPHPClass($elRefClass, $element->getReferencedElement()); + $elRef = $element->getReferencedElement(); + $elRefClass = $this->visitElementDef($elRef); + $refType = $this->findPHPClass($elRefClass, $elRef); - if ($this->typeHasValue($element->getReferencedElement()->getType(), $elRefClass, $element->getReferencedElement())) { + if ($this->typeHasValue($elRef->getType(), $elRefClass, $elRef->getName())) { return $refType; } } diff --git a/src/Php/Structure/PHPArg.php b/src/Php/Structure/PHPArg.php index 38ea63a4..90a6f44b 100644 --- a/src/Php/Structure/PHPArg.php +++ b/src/Php/Structure/PHPArg.php @@ -4,79 +4,76 @@ class PHPArg { - protected $doc; + protected ?string $doc = null; - protected $type; + protected ?PHPClass $type = null; - protected $name; + protected ?string $name = null; - protected $nullable = false; - - protected $default; + protected bool $nullable = false; - public function __construct($name = null, $type = null) + protected string|array|null $default = null; + + public function __construct(?string $name = null, ?PHPClass $type = null) { $this->name = $name; $this->type = $type; } - public function getDoc() + public function getDoc(): ?string { return $this->doc; } - public function setDoc($doc) + public function setDoc(?string $doc): static { $this->doc = $doc; return $this; } - /** - * @return PHPClass - */ - public function getType() + public function getType(): ?PHPClass { return $this->type; } - public function setType(PHPClass $type) + public function setType(?PHPClass $type): PHPArg { $this->type = $type; return $this; } - public function getName() + public function getName(): ?string { return $this->name; } - public function setName($name) + public function setName(?string $name): PHPArg { $this->name = $name; return $this; } - public function getNullable() + public function getNullable(): bool { return $this->nullable; } - public function setNullable($nullable) + public function setNullable(bool $nullable): PHPArg { $this->nullable = $nullable; - + return $this; } - - public function getDefault() + + public function getDefault(): string|array|null { return $this->default; } - public function setDefault($default) + public function setDefault(string|array|null $default): PHPArg { $this->default = $default; diff --git a/src/Php/Structure/PHPClass.php b/src/Php/Structure/PHPClass.php index e689aabd..44e4b2a2 100644 --- a/src/Php/Structure/PHPClass.php +++ b/src/Php/Structure/PHPClass.php @@ -4,15 +4,37 @@ class PHPClass { - protected $name; + protected ?string $name; - protected $namespace; + protected ?string $namespace; - protected $doc; + protected ?string $doc = null; - protected $implements = []; + protected array $implements = []; - public static function createFromFQCN($className) + protected array $checks = []; + + /** + * @var PHPConstant[] + */ + protected array $constants = []; + + /** + * @var PHPProperty[] + */ + protected array $properties = []; + + protected bool $abstract = false; + + protected ?PHPClass $extends = null; + + public function __construct(?string $name = null, ?string $namespace = null) + { + $this->name = $name; + $this->namespace = $namespace; + } + + public static function createFromFQCN(string $className): static { if (($pos = strrpos($className, '\\')) !== false) { return new self(substr($className, $pos + 1), substr($className, 0, $pos)); @@ -21,20 +43,12 @@ public static function createFromFQCN($className) } } - /** - * @return array - */ public function getImplements(): array { return $this->implements; } - /** - * @param bool $onlyParent - * - * @return PHPProperty - */ - public function isSimpleType($onlyParent = false) + public function isSimpleType(bool $onlyParent = false): ?PHPProperty { if ($onlyParent) { $e = $this->getExtends(); @@ -48,14 +62,16 @@ public function isSimpleType($onlyParent = false) return $this->getPropertyInHierarchy('__value'); } } + + return null; } - public function setImplements(array $fqcn) + public function setImplements(array $fqcn): void { $this->implements = $fqcn; } - public function getPhpType() + public function getPhpType(): string { if (!$this->getNamespace()) { if ($this->isNativeType()) { @@ -68,7 +84,7 @@ public function getPhpType() return '\\' . $this->getFullName(); } - public function isNativeType() + public function isNativeType(): bool { return !$this->getNamespace() && in_array($this->getName(), [ 'string', @@ -82,92 +98,58 @@ public function isNativeType() ]); } - public function __construct($name = null, $namespace = null) - { - $this->name = $name; - $this->namespace = $namespace; - } - - public function getName() + public function getName(): ?string { return $this->name; } - public function setName($name) + public function setName(?string $name): static { $this->name = $name; return $this; } - public function getNamespace() + public function getNamespace(): ?string { return $this->namespace; } - public function setNamespace($namespace) + public function setNamespace(?string $namespace): static { $this->namespace = $namespace; return $this; } - public function getDoc() + public function getDoc(): ?string { return $this->doc; } - public function setDoc($doc) + public function setDoc(string $doc): static { $this->doc = $doc; return $this; } - public function __toString() + public function __toString(): string { return $this->getFullName(); } - public function getFullName() + public function getFullName(): string { return "{$this->namespace}\\{$this->name}"; } - protected $checks = []; - - /** - * @var PHPConstant[] - */ - protected $constants = []; - - /** - * @var PHPProperty[] - */ - protected $properties = []; - - /** - * @param - * $property - * - * @return array - */ - public function getChecks($property) + public function getChecks(string $property): array { - return isset($this->checks[$property]) ? $this->checks[$property] : []; + return $this->checks[$property] ?? []; } - /** - * @param - * $property - * @param - * $check - * @param - * $value - * - * @return $this - */ - public function addCheck($property, $check, $value) + public function addCheck(string $property, string $check, mixed $value): static { $this->checks[$property][$check][] = $value; @@ -177,56 +159,36 @@ public function addCheck($property, $check, $value) /** * @return PHPProperty[] */ - public function getProperties() + public function getProperties(): array { return $this->properties; } - /** - * @param string $name - * - * @return bool - */ - public function hasProperty($name) + public function hasProperty(string $name): bool { return isset($this->properties[$name]); } - /** - * @param string $name - * - * @return bool - */ - public function hasPropertyInHierarchy($name) + public function hasPropertyInHierarchy(string $name, bool $onlyParents = false): bool { - if (count($this->getProperties()) > 1 || (count($this->getProperties()) > 0 && !$this->hasProperty($name))) { - return false; - } - if ($this->hasProperty($name)) { + if (!$onlyParents && $this->hasProperty($name)) { return true; } - if (($this instanceof PHPClass) && $this->getExtends() && $this->getExtends()->hasPropertyInHierarchy($name)) { + + if ($this->getExtends() && $this->getExtends()->hasPropertyInHierarchy($name)) { return true; } return false; } - /** - * @param string $name - * - * @return PHPProperty - */ - public function getPropertyInHierarchy($name) + public function getPropertyInHierarchy(string $name, bool $onlyParents = false): ?PHPProperty { - if (count($this->getProperties()) > 1 || (count($this->getProperties()) > 0 && !$this->hasProperty($name))) { - return null; - } - - if ($this->hasProperty($name)) { + if (!$onlyParents && $this->hasProperty($name)) { return $this->getProperty($name); } - if (($this instanceof PHPClass) && $this->getExtends() && $this->getExtends()->hasPropertyInHierarchy($name)) { + + if ($this->getExtends() && $this->getExtends()->hasPropertyInHierarchy($name)) { return $this->getExtends()->getPropertyInHierarchy($name); } @@ -234,11 +196,9 @@ public function getPropertyInHierarchy($name) } /** - * @param string $name - * - * @return PHPProperty + * @return PHPProperty[] */ - public function getPropertiesInHierarchy() + public function getPropertiesInHierarchy(): array { $ps = $this->getProperties(); @@ -249,62 +209,38 @@ public function getPropertiesInHierarchy() return $ps; } - /** - * @param string $name - * - * @return PHPProperty - */ - public function getProperty($name) + public function getProperty(string $name): ?PHPProperty { - return $this->properties[$name]; + return $this->properties[$name] ?? null; } - /** - * @return $this - */ - public function addProperty(PHPProperty $property) + public function addProperty(PHPProperty $property): static { $this->properties[$property->getName()] = $property; return $this; } - /** - * @var bool - */ - protected $abstract; - - /** - * @var PHPClass - */ - protected $extends; - - /** - * @return PHPClass - */ - public function getExtends() + public function getExtends(): ?PHPClass { return $this->extends; } - /** - * @return PHPClass - */ - public function setExtends(PHPClass $extends) + public function setExtends(PHPClass $extends): static { $this->extends = $extends; return $this; } - public function getAbstract() + public function getAbstract(): bool { return $this->abstract; } - public function setAbstract($abstract) + public function setAbstract(bool $abstract): static { - $this->abstract = (bool) $abstract; + $this->abstract = $abstract; return $this; } diff --git a/src/Php/Structure/PHPClassOf.php b/src/Php/Structure/PHPClassOf.php index b53feda2..9d5dbd6a 100644 --- a/src/Php/Structure/PHPClassOf.php +++ b/src/Php/Structure/PHPClassOf.php @@ -4,10 +4,7 @@ class PHPClassOf extends PHPClass { - /** - * @var PHPArg - */ - protected $arg; + protected PHPArg $arg; public function __construct(PHPArg $arg) { @@ -18,15 +15,12 @@ public function __construct(PHPArg $arg) /** * @return string */ - public function __toString() + public function __toString(): string { return 'array of ' . $this->arg; } - /** - * @return PHPArg - */ - public function getArg() + public function getArg(): PHPArg { return $this->arg; } diff --git a/src/Php/Structure/PHPProperty.php b/src/Php/Structure/PHPProperty.php index 4c328303..5bd1e7b3 100644 --- a/src/Php/Structure/PHPProperty.php +++ b/src/Php/Structure/PHPProperty.php @@ -2,30 +2,34 @@ namespace GoetasWebservices\Xsd\XsdToPhp\Php\Structure; +use Laminas\Code\Generator\AbstractMemberGenerator; + class PHPProperty extends PHPArg { - /** - * @var string - */ - protected $visibility = 'protected'; - - /** - * @return string - */ - public function getVisibility() + protected string $visibility = AbstractMemberGenerator::VISIBILITY_PROTECTED; + protected ?string $fixed = null; + + public function getVisibility(): string { return $this->visibility; } - /** - * @param string $visibility - * - * @return $this - */ - public function setVisibility($visibility) + public function setVisibility(string $visibility): static { $this->visibility = $visibility; return $this; } + + public function getFixed(): ?string + { + return $this->fixed; + } + + public function setFixed(?string $fixed): static + { + $this->fixed = $fixed; + + return $this; + } } diff --git a/tests/Converter/JMS/Xsd2JmsElementTest.php b/tests/Converter/JMS/Xsd2JmsElementTest.php index a4759ae8..8822d91f 100644 --- a/tests/Converter/JMS/Xsd2JmsElementTest.php +++ b/tests/Converter/JMS/Xsd2JmsElementTest.php @@ -2,7 +2,7 @@ namespace GoetasWebservices\Xsd\XsdToPhp\Tests\Converter\JMS; -class Xsd2PhpElementTest extends Xsd2JmsBase +class Xsd2JmsElementTest extends Xsd2JmsBase { /** * @dataProvider getPrimitiveTypeConversions @@ -324,6 +324,8 @@ public function testSetterNamingStrategy() ], ], ], - ], $classes); + ], + $classes + ); } } diff --git a/tests/Converter/JMS/Xsd2JmsGroupTest.php b/tests/Converter/JMS/Xsd2JmsGroupTest.php index fc5b09ee..96baa155 100644 --- a/tests/Converter/JMS/Xsd2JmsGroupTest.php +++ b/tests/Converter/JMS/Xsd2JmsGroupTest.php @@ -2,7 +2,7 @@ namespace GoetasWebservices\Xsd\XsdToPhp\Tests\Converter\JMS; -class Xsd2PhpGroupTest extends Xsd2JmsBase +class Xsd2JmsGroupTest extends Xsd2JmsBase { public function testGroupArray() { @@ -183,7 +183,9 @@ public function testSomeAnonymous() ], ], ], - ], $classes['Example\\ComplexType1Type']); + ], + $classes['Example\\ComplexType1Type'] + ); $this->assertEquals( [ @@ -206,7 +208,9 @@ public function testSomeAnonymous() ], ], ], - ], $classes['Example\\ComplexType1Type\\String2AType']); + ], + $classes['Example\\ComplexType1Type\\String2AType'] + ); } public function testSomeAnonymousWithRefs() @@ -306,7 +310,9 @@ public function testSomeInheritance() ], ], ], - ], $classes['Example\\ComplexType1Type']); + ], + $classes['Example\\ComplexType1Type'] + ); $this->assertEquals( [ @@ -340,7 +346,9 @@ public function testSomeInheritance() ], ], ], - ], $classes['Example\\ComplexType2Type']); + ], + $classes['Example\\ComplexType2Type'] + ); } public function getMaxOccurs() @@ -412,7 +420,9 @@ public function testArray() ], ], ], - ], $classes['Example\\ComplexType1Type']); + ], + $classes['Example\\ComplexType1Type'] + ); } /** @@ -453,7 +463,9 @@ public function testMaxOccurs($max, $isArray) ], ], ], - ], $classes['Example\\ComplexType1Type']); + ], + $classes['Example\\ComplexType1Type'] + ); } public function testGeneralParts() @@ -606,7 +618,9 @@ public function testGeneralParts() ], ], ], - ], $classes['Example\\ComplexType1Type']); + ], + $classes['Example\\ComplexType1Type'] + ); } public function testListOfRestriction() diff --git a/tests/JmsSerializer/OTA/OTASerializationTest.php b/tests/JmsSerializer/OTA/OTASerializationTest.php index 311ec057..6f59191d 100644 --- a/tests/JmsSerializer/OTA/OTASerializationTest.php +++ b/tests/JmsSerializer/OTA/OTASerializationTest.php @@ -39,7 +39,7 @@ public static function setUpBeforeClass(): void ['http://www.opentravel.org/OTA/2003/05', 'DateOrTimeOrDateTimeType', 'GoetasWebservices\Xsd\XsdToPhp\Tests\JmsSerializer\OTA\OTADateTime'], ['http://www.opentravel.org/OTA/2003/05', 'DateOrDateTimeType', 'GoetasWebservices\Xsd\XsdToPhp\Tests\JmsSerializer\OTA\OTADateTime'], ['http://www.opentravel.org/OTA/2003/05', 'TimeOrDateTimeType', 'GoetasWebservices\Xsd\XsdToPhp\Tests\JmsSerializer\OTA\OTADateTime'], - ], __DIR__ .'/zz'); + ], __DIR__ . '/zz'); $reader = new SchemaReader(); $schemas = []; @@ -144,7 +144,7 @@ protected function clearXML($xml) */ public function testConversion($xml, $xsd, $class) { - if (!class_exists('XMLDiff\Memory', false)){ + if (!class_exists('XMLDiff\Memory', false)) { $this->markTestSkipped('XMLDiff not installed'); } diff --git a/tests/PHP/AnyPHPConversionTest.php b/tests/PHP/AnyPHPConversionTest.php new file mode 100644 index 00000000..f3ceb864 --- /dev/null +++ b/tests/PHP/AnyPHPConversionTest.php @@ -0,0 +1,82 @@ + + + + + + + + + + + + '; + + public function testSimpleAnyPHP(): void + { + $items = $this->getPhpClasses(self::XML); + + $this->assertCount(2, $items); + + $type = $items['Example\FormulardateiXMLType']; + $method = $type->getMethod('setXmldaten'); + $this->assertTrue($method !== false); + $this->assertTrue($method->getParameters()['xmldaten']->getType() === 'Example\AnyXMLContentType'); + + $type = $items['Example\AnyXMLContentType']; + $method = $type->getMethod('setAny'); + $this->assertTrue($method !== false); + $this->assertTrue($method->getParameters()['any']->getType() === null); + } + + public function testSimpleAnyTypeYaml() + { + $items = $this->getYamlFiles(self::XML); + + $this->assertCount(2, $items); + $this->assertEquals([ + 'Example\\AnyXMLContentType' => [ + 'properties' => [ + 'any' => [ + 'expose' => true, + 'access_type' => 'public_method', + 'serialized_name' => 'any', + 'accessor' => [ + 'getter' => 'getAny', + 'setter' => 'setAny', + ], + ], + ], + ], + ], $items['Example\AnyXMLContentType']); + $this->assertEquals([ + 'Example\\FormulardateiXMLType' => [ + 'properties' => [ + 'xmldaten' => [ + 'expose' => true, + 'access_type' => 'public_method', + 'serialized_name' => 'xmldaten', + 'accessor' => [ + 'getter' => 'getXmldaten', + 'setter' => 'setXmldaten', + ], + 'type' => 'Example\\AnyXMLContentType', + ], + ], + ], + ], $items['Example\FormulardateiXMLType']); + } +} diff --git a/tests/PHP/AnyTypePHPConversionTest.php b/tests/PHP/AnyTypePHPConversionTest.php index f4f01c93..76bd0373 100644 --- a/tests/PHP/AnyTypePHPConversionTest.php +++ b/tests/PHP/AnyTypePHPConversionTest.php @@ -1,85 +1,12 @@ addNamespace('', 'Example'); - - foreach ($types as $typeData) { - list($ns, $name, $type) = $typeData; - $creator->addAliasMapType($ns, $name, $type); - } - - $reader = new SchemaReader(); - - if (!is_array($xml)) { - $xml = [ - 'schema.xsd' => $xml, - ]; - } - $schemas = []; - foreach ($xml as $name => $str) { - $schemas[] = $reader->readString($str, $name); - } - $items = $creator->convert($schemas); - - return $items; - } - - /** - * @param mixed $xml - * - * @return \Laminas\Code\Generator\ClassGenerator[] - */ - protected function getPhpClasses($xml, array $types = []) - { - $creator = new PhpConverter(new ShortNamingStrategy()); - $creator->addNamespace('', 'Example'); - - foreach ($types as $typeData) { - list($ns, $name, $type) = $typeData; - $creator->addAliasMapType($ns, $name, $type); - } - - $generator = new ClassGenerator(); - $reader = new SchemaReader(); - - if (!is_array($xml)) { - $xml = [ - 'schema.xsd' => $xml, - ]; - } - $schemas = []; - foreach ($xml as $name => $str) { - $schemas[] = $reader->readString($str, $name); - } - $items = $creator->convert($schemas); - - $classes = []; - foreach ($items as $k => $item) { - if ($codegen = $generator->generate($item)) { - $classes[$k] = $codegen; - } - } - - return $classes; - } + use GetPhpYamlTrait; public function testSimpleAnyTypePHP() { diff --git a/tests/PHP/GetPhpYamlTrait.php b/tests/PHP/GetPhpYamlTrait.php new file mode 100644 index 00000000..73be7f6c --- /dev/null +++ b/tests/PHP/GetPhpYamlTrait.php @@ -0,0 +1,85 @@ +addNamespace('', 'Example'); + + foreach ($types as $typeData) { + list($ns, $name, $type) = $typeData; + $creator->addAliasMapType($ns, $name, $type); + } + + $reader = new SchemaReader(); + + if (!is_array($xml)) { + $xml = [ + 'schema.xsd' => $xml, + ]; + } + $schemas = []; + foreach ($xml as $name => $str) { + $schemas[] = $reader->readString($str, $name); + } + $items = $creator->convert($schemas); + + return $items; + } + + /** + * @param array|string $xml + * @param array $types + * + * @return \Laminas\Code\Generator\ClassGenerator[] + */ + protected function getPhpClasses($xml, array $types = []) + { + $creator = new PhpConverter(new ShortNamingStrategy()); + $creator->addNamespace('', 'Example'); + + foreach ($types as $typeData) { + list($ns, $name, $type) = $typeData; + $creator->addAliasMapType($ns, $name, $type); + } + + $generator = new ClassGenerator(); + $reader = new SchemaReader(); + + if (!is_array($xml)) { + $xml = [ + 'schema.xsd' => $xml, + ]; + } + $schemas = []; + foreach ($xml as $name => $str) { + $schemas[] = $reader->readString($str, $name); + } + $items = $creator->convert($schemas); + + $classes = []; + foreach ($items as $k => $item) { + if ($codegen = $generator->generate($item)) { + $classes[$k] = $codegen; + } + } + + return $classes; + } +} diff --git a/tests/PHP/PHPConversionTest.php b/tests/PHP/PHPConversionTest.php index 37e9b494..d5fb7219 100644 --- a/tests/PHP/PHPConversionTest.php +++ b/tests/PHP/PHPConversionTest.php @@ -1,54 +1,17 @@ addNamespace('http://www.example.com', 'Example'); - - $generator = new ClassGenerator(); - $reader = new SchemaReader(); - - if (!is_array($xml)) { - $xml = [ - 'schema.xsd' => $xml, - ]; - } - $schemas = []; - foreach ($xml as $name => $str) { - $schemas[] = $reader->readString($str, $name); - } - $items = $phpcreator->convert($schemas); - - $classes = []; - foreach ($items as $k => $item) { - if ($codegen = $generator->generate($item)) { - $classes[$k] = $codegen; - } - } - - return $classes; - } + use GetPhpYamlTrait; - public function testSimpleContent() + public function testSimpleContent(): void { $xml = ' - + @@ -58,7 +21,7 @@ public function testSimpleContent() '; - $items = $this->getClasses($xml); + $items = $this->getPhpClasses($xml); $this->assertCount(1, $items); $codegen = $items['Example\SingleType']; @@ -71,11 +34,10 @@ public function testSimpleContent() $this->assertTrue($codegen->hasMethod('setCode')); } - public function testSimpleNoAttributesContent() + public function testSimpleNoAttributesContent(): void { $xml = ' - + @@ -86,7 +48,7 @@ public function testSimpleNoAttributesContent() '; - $items = $this->getClasses($xml); + $items = $this->getPhpClasses($xml); $this->assertCount(1, $items); $codegen = $items['Example\SingleType']; @@ -96,11 +58,10 @@ public function testSimpleNoAttributesContent() $this->assertTrue($codegen->hasMethod('__toString')); } - public function testNoMulteplicity() + public function testNoMulteplicity(): void { $xml = ' - + @@ -108,7 +69,7 @@ public function testNoMulteplicity() '; - $items = $this->getClasses($xml); + $items = $this->getPhpClasses($xml); $this->assertCount(1, $items); $codegen = $items['Example\SingleType']; @@ -119,11 +80,10 @@ public function testNoMulteplicity() $this->assertTrue($codegen->hasMethod('setId')); } - public function testMulteplicity() + public function testMulteplicity(): void { $xml = ' - + @@ -136,7 +96,7 @@ public function testMulteplicity() '; - $items = $this->getClasses($xml); + $items = $this->getPhpClasses($xml); $this->assertCount(2, $items); @@ -151,10 +111,10 @@ public function testMulteplicity() $this->assertNull($codegen->getMethod('issetId')->getParameters()['index']->getType()); } - public function testNestedMulteplicity() + public function testNestedMulteplicity(): void { $xml = ' - + @@ -172,7 +132,7 @@ public function testNestedMulteplicity() '; - $items = $this->getClasses($xml); + $items = $this->getPhpClasses($xml); $this->assertCount(3, $items); @@ -197,25 +157,21 @@ public function testNestedMulteplicity() public function testMultipleArrayTypes() { $xml = ' - - + - - '; - $items = $this->getClasses($xml); + $items = $this->getPhpClasses($xml); $this->assertCount(2, $items); @@ -231,8 +187,7 @@ public function testMultipleArrayTypes() public function testSimpleMulteplicity() { $xml = ' - + @@ -243,7 +198,7 @@ public function testSimpleMulteplicity() '; - $items = $this->getClasses($xml); + $items = $this->getPhpClasses($xml); $this->assertCount(1, $items); @@ -258,8 +213,7 @@ public function testSimpleMulteplicity() public function testNillableElement() { $xml = ' - + @@ -270,11 +224,11 @@ public function testNillableElement() '; - $items = $this->getClasses($xml); + $items = $this->getPhpClasses($xml); $codegen = $items['Example\SingleType']; $this->assertTrue($codegen->hasMethod('setDate1')); - $this->assertNull($codegen->getMethod('setDate1')->getParameters()['date1']->getDefaultValue()->getValue()); + $this->assertNull($codegen->getMethod('setDate1')->getParameters()['date1']->getDefaultValue()); $this->assertTrue($codegen->hasMethod('setDate2')); $this->assertNull($codegen->getMethod('setDate2')->getParameters()['date2']->getDefaultValue()); $this->assertTrue($codegen->hasMethod('setStr1')); @@ -282,4 +236,64 @@ public function testNillableElement() $this->assertTrue($codegen->hasMethod('setStr2')); $this->assertNull($codegen->getMethod('setStr2')->getParameters()['str2']->getDefaultValue()); } + + public function testNoCodeDuplicationInExtendingClass(): void + { + $xml = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + + $items = $this->getPhpClasses($xml); + $codeType = $items['Example\CodeType']; + $codeZeitserientypType = $items['Example\CodeZeitserientypType']; + + $this->assertTrue($codeType->hasMethod('setCode')); + $this->assertTrue($codeType->hasMethod('getCode')); + $this->assertTrue($codeType->hasMethod('setName')); + $this->assertTrue($codeType->hasMethod('getName')); + $this->assertTrue($codeType->hasMethod('setListURI')); + $this->assertTrue($codeType->hasMethod('getListURI')); + $this->assertNull($codeType->getProperty('listURI')->getDefaultValue()); + $this->assertTrue($codeType->hasMethod('setListVersionID')); + $this->assertTrue($codeType->hasMethod('getListVersionID')); + $this->assertNull($codeType->getProperty('listVersionID')->getDefaultValue()); + $this->assertTrue($codeZeitserientypType->getExtendedClass() === 'Example\CodeType'); + $this->assertFalse($codeZeitserientypType->hasMethod('setCode')); + $this->assertFalse($codeZeitserientypType->hasMethod('getCode')); + $this->assertFalse($codeZeitserientypType->hasMethod('setName')); + $this->assertFalse($codeZeitserientypType->hasMethod('getName')); + $this->assertFalse($codeZeitserientypType->hasMethod('setListURI')); + $this->assertFalse($codeZeitserientypType->hasMethod('getListURI')); + $value = $codeZeitserientypType->getProperty('listURI')->getDefaultValue()->getValue(); + $this->assertTrue($value === "urn:xoev-de:fim:codeliste:xzufi.zeitserientyp"); + $this->assertFalse($codeZeitserientypType->hasMethod('setListVersionID')); + $this->assertFalse($codeZeitserientypType->hasMethod('getListVersionID')); + $value = $codeZeitserientypType->getProperty('listVersionID')->getDefaultValue()->getValue(); + $this->assertTrue($value === "1.1"); + } }