public function testEasyPoXSD() { $filepath = dirname(__FILE__) . '/../../_files/EasyPO/'; $schema = simplexml_load_file($filepath . '/easypo.xsd'); $parser = new PiBX_CodeGen_SchemaParser(); $parser->setSchema($schema); $parsedTree = $parser->parse(); $namespaces = array('xs' => 'http://www.w3.org/2001/XMLSchema', 'po' => 'http://openuri.org/easypo'); $expectedTypeList = array(); $expectedType1 = new PiBX_AST_Type('purchase-order'); $expectedType1->setAsRoot(); $expectedType1->setTargetNamespace('http://openuri.org/easypo'); $expectedType1->setNamespaces($namespaces); $expectedType1->add(new PiBX_AST_TypeAttribute('customer', 'customer')); $expectedType1->add(new PiBX_AST_TypeAttribute('date', 'dateTime')); $ta = new PiBX_AST_TypeAttribute('line-item', 'line-item'); $ta->add(new PiBX_AST_CollectionItem('line-item', 'line-item')); $expectedType1->add($ta); $expectedType1->add(new PiBX_AST_TypeAttribute('shipper', 'shipper')); $expectedType2 = new PiBX_AST_Type('customer'); $expectedType2->add(new PiBX_AST_TypeAttribute('name', 'string')); $expectedType2->add(new PiBX_AST_TypeAttribute('address', 'string')); $ta = new PiBX_AST_TypeAttribute('age', 'int'); $ta->setStyle('attribute'); $expectedType2->add($ta); $ta = new PiBX_AST_TypeAttribute('moo', 'int'); $ta->setStyle('attribute'); $expectedType2->add($ta); $ta = new PiBX_AST_TypeAttribute('poo', 'int'); $ta->setStyle('attribute'); $expectedType2->add($ta); $expectedType3 = new PiBX_AST_Type('line-item'); $expectedType3->add(new PiBX_AST_TypeAttribute('description', 'string')); $expectedType3->add(new PiBX_AST_TypeAttribute('per-unit-ounces', 'decimal')); $expectedType3->add(new PiBX_AST_TypeAttribute('price', 'decimal')); $expectedType3->add(new PiBX_AST_TypeAttribute('quantity', 'integer')); $expectedType4 = new PiBX_AST_Type('shipper'); $expectedType4->add(new PiBX_AST_TypeAttribute('name', 'string')); $expectedType4->add(new PiBX_AST_TypeAttribute('per-ounce-rate', 'decimal')); $parser = new PiBX_CodeGen_SchemaParser(); $parser->setSchema($schema); $tree = $parser->parse(); $creator = new PiBX_CodeGen_ASTCreator(new PiBX_CodeGen_TypeUsage()); $tree->accept($creator); $typeList = $creator->getTypeList(); $this->assertEquals(4, count($typeList)); $this->assertEquals($expectedType1, $typeList[0]); $this->assertEquals($expectedType2, $typeList[1]); $this->assertEquals($expectedType3, $typeList[2]); $this->assertEquals($expectedType4, $typeList[3]); }
private function parseTypeAttribute(SimpleXMLElement $xml, PiBX_AST_TypeAttribute $ast, $parentObject) { $name = $ast->getName(); if ($ast->getStyle() == 'element') { $value = (string) $xml->{$name}; } elseif ($ast->getStyle() == 'attribute') { $attributes = $xml->attributes(); $value = (string) $attributes[$name]; } $setter = $ast->getSetMethod(); $parentObject->{$setter}($value); return $parentObject; }
private function parseMapping(SimpleXMLElement $xml, PiBX_AST_Tree $part) { $nodes = $xml->xpath('./*'); foreach ($nodes as &$child) { $name = (string) $child->getName(); $attributes = $child->attributes(); if ($name == 'collection') { $name = (string) $attributes['name']; $setter = (string) $attributes['set-method']; $getter = (string) $attributes['get-method']; $newPart = new PiBX_AST_Collection($name); $newPart->setSetMethod($setter); $newPart->setGetMethod($getter); $class = (string) $attributes['class']; $this->classMap[$name] = $class; $this->elementAsts[$name] = $newPart; $this->parseMapping($child, $newPart); } elseif ($name == 'structure') { $name = (string) $attributes['name']; if ($part instanceof PiBX_AST_Collection) { // a structure in a collection is a reference to the actual structure $referencedType = (string) $attributes['map-as']; $type = $this->getClassnameForName($referencedType); $newPart = new PiBX_AST_Structure($name); $newPart->setType($type); $this->structuralReferences[$referencedType] = $name; } elseif ($part instanceof PiBX_AST_Type) { $referencedType = (string) $attributes['map-as']; $type = $this->getClassnameForName($referencedType); // a structure in a type is the structure "container" $newPart = new PiBX_AST_Structure($name, $type); $getMethod = (string) $attributes['get-method']; $setMethod = (string) $attributes['set-method']; $newPart->setGetMethod($getMethod); $newPart->setSetMethod($setMethod); } elseif ($part instanceof PiBX_AST_Structure) { $ordered = (string) $attributes['ordered']; $ordered = strtolower($ordered); $choice = (string) $attributes['choice']; $choice = strtolower($choice); if ($ordered == 'true' && $choice == 'false') { $part->setStructureType(PiBX_AST_StructureType::ORDERED()); } elseif ($ordered == 'false' && $choice == 'true') { $part->setStructureType(PiBX_AST_StructureType::CHOICE()); } else { throw new RuntimeException('Invalid structure state!'); } $structureValues = $child->xpath('./*'); // this handling is a bit clunky but needed, // since the choice structures are defined // somewhat redundant in the binding.xml foreach ($structureValues as &$struct) { $valueName = (string) $struct->getName(); if ($valueName != 'value') { throw new RuntimeException('No value-element within the structure.'); } $attributes = $struct->attributes(); $nameAttribute = (string) $attributes['name']; $newPart = new PiBX_AST_StructureElement($nameAttribute); $style = (string) $attributes['style']; $testMethod = (string) $attributes['test-method']; $getMethod = (string) $attributes['get-method']; $setMethod = (string) $attributes['set-method']; $newPart->setStyle($style); $newPart->setTestMethod($testMethod); $newPart->setGetMethod($getMethod); $newPart->setSetMethod($setMethod); $part->add($newPart); $this->elementAsts[$nameAttribute] = $newPart; } // no further processing needed // all structure values have been added break; } $this->elementAsts[$name] = $newPart; $this->parseMapping($child, $newPart); } elseif ($name == 'value') { $name = (string) $attributes['name']; if ($part instanceof PiBX_AST_Collection) { $newPart = new PiBX_AST_CollectionItem($name); } elseif ($part instanceof PiBX_AST_Type) { $newPart = new PiBX_AST_TypeAttribute($name); $style = (string) $attributes['style']; $setMethod = (string) $attributes['set-method']; $getMethod = (string) $attributes['get-method']; $newPart->setStyle($style); $newPart->setSetMethod($setMethod); $newPart->setGetMethod($getMethod); } $this->elementAsts[$name] = $newPart; } else { throw new InvalidArgumentException('Unexpected binding element "' . $name . '"'); } $part->add($newPart); } }
function visitElementNode(PiBX_ParseTree_Tree $tree) { $this->plowTypesForLevel($tree->getLevel()); $logMessage = $tree->getLevel() . str_pad(" ", $tree->getLevel()) . " element"; if ($tree->isAnonym()) { $logMessage .= " <anonym>"; } else { $logMessage .= " (" . $tree->getName() . ")"; } if ($tree->getLevel() > 0) { if ($this->currentType() instanceof PiBX_AST_Type) { $ta = new PiBX_AST_TypeAttribute($tree->getName()); $ta->setType($tree->getType()); $schemaType = $tree->getType(); $sf = new PiBX_CodeGen_ASTStackFrame($tree->getLevel(), $ta); array_push($this->stack, $sf); // elements with maxOccurs "unbounded" are collections/lists // with no parent collection element. if ($tree->getMaxOccurs() == 'unbounded') { $ci = new PiBX_AST_CollectionItem($tree->getName()); $ci->setType($tree->getType()); $sf = new PiBX_CodeGen_ASTStackFrame($tree->getLevel(), $ci); array_push($this->stack, $sf); } } elseif ($this->currentType() instanceof PiBX_AST_Collection) { $ci = new PiBX_AST_CollectionItem($tree->getName()); $ci->setType($tree->getType()); $sf = new PiBX_CodeGen_ASTStackFrame($tree->getLevel(), $ci); array_push($this->stack, $sf); } elseif ($this->currentType() instanceof PiBX_AST_Structure) { $se = new PiBX_AST_StructureElement($tree->getName(), $tree->getType()); $sf = new PiBX_CodeGen_ASTStackFrame($tree->getLevel(), $se); array_push($this->stack, $sf); } } elseif ($tree->getLevel() == 0) { $logMessage .= " - global"; $t = new PiBX_AST_Type($tree->getName()); if ($this->countTypes() == 0) { // the first type is the XSD-root. $t->setAsRoot(); $t->setTargetNamespace($tree->getParent()->getTargetNamespace()); $t->setNamespaces($tree->getNamespaces()); } $sf = new PiBX_CodeGen_ASTStackFrame(-1, $t); array_push($this->stack, $sf); /* * Yes, add it two times. * It's a limitation that exist in the current implementation * of the TypeUsage-class. * The concrete class (which is the root element/type of a schema) * will not be referenced more than one time (at the definition). * But it must not be removed in an AST optimization afterwards, * so we just increase the usage-counter by one. */ $this->typeUsage->addType($tree->getName()); $this->typeUsage->addType($tree->getName()); } else { throw new RuntimeException('invalid element state'); } $this->lastLevel = $tree->getLevel(); $this->log($logMessage); }
public function testBooksBinding() { $filepath = dirname(__FILE__) . '/../_files/Books'; $bindingFile = $filepath . '/binding.xml'; $expectedXml = file_get_contents($bindingFile); $binding = new PiBX_Runtime_Binding($bindingFile); $asts = $binding->parse(); $this->assertEquals(2, count($asts)); // first tree/type $expectedAst1 = new PiBX_AST_Type('Collection'); $expectedAst1->setType('Collection'); $expectedAst1->setAsRoot(); $collection = new PiBX_AST_Collection('books'); $collection->setGetMethod('getBooks'); $collection->setSetMethod('setBooks'); $structure = new PiBX_AST_Structure('book'); $structure->setType('BookType'); $expectedAst1->add($collection->add($structure)); $this->assertEquals($expectedAst1, $asts[0]); // second tree/type $expectedAst2 = new PiBX_AST_Type('bookType'); $expectedAst2->setType('BookType'); $value1 = new PiBX_AST_TypeAttribute('name'); $value1->setStyle('element'); $value1->setGetMethod('getName'); $value1->setSetMethod('setName'); $expectedAst2->add($value1); $value2 = new PiBX_AST_TypeAttribute('ISBN'); $value2->setStyle('element'); $value2->setGetMethod('getISBN'); $value2->setSetMethod('setISBN'); $expectedAst2->add($value2); $value3 = new PiBX_AST_TypeAttribute('price'); $value3->setStyle('element'); $value3->setGetMethod('getPrice'); $value3->setSetMethod('setPrice'); $expectedAst2->add($value3); $value4 = new PiBX_AST_Collection('authors'); $value4->setGetMethod('getAuthorNames'); $value4->setSetMethod('setAuthorNames'); $value4item = new PiBX_AST_CollectionItem('authorName'); $value4->add($value4item); $expectedAst2->add($value4); $value5 = new PiBX_AST_TypeAttribute('description'); $value5->setStyle('element'); $value5->setGetMethod('getDescription'); $value5->setSetMethod('setDescription'); $expectedAst2->add($value5); $value6 = new PiBX_AST_Structure('promotion'); $value6->setStructureType(PiBX_AST_StructureType::CHOICE()); $value6Item1 = new PiBX_AST_StructureElement('Discount'); $value6Item1->setTestMethod('ifPromotionDiscount'); $value6Item1->setGetMethod('getPromotionDiscount'); $value6Item1->setSetMethod('setPromotionDiscount'); $value6Item1->setStyle('element'); $value6Item2 = new PiBX_AST_StructureElement('None'); $value6Item2->setTestMethod('ifPromotionNone'); $value6Item2->setGetMethod('getPromotionNone'); $value6Item2->setSetMethod('setPromotionNone'); $value6Item2->setStyle('element'); $value6->add($value6Item1); $value6->add($value6Item2); $expectedAst2->add($value6); $value7 = new PiBX_AST_TypeAttribute('publicationDate'); $value7->setStyle('element'); $value7->setGetMethod('getPublicationDate'); $value7->setSetMethod('setPublicationDate'); $expectedAst2->add($value7); $value8 = new PiBX_AST_TypeAttribute('bookCategory'); $value8->setStyle('element'); $value8->setGetMethod('getBookCategory'); $value8->setSetMethod('setBookCategory'); $expectedAst2->add($value8); $value9 = new PiBX_AST_TypeAttribute('itemId'); $value9->setStyle('attribute'); $value9->setGetMethod('getItemId'); $value9->setSetMethod('setItemId'); $expectedAst2->add($value9); $this->assertEquals($expectedAst2, $asts[1]); }
public function testBooksExampleXSD() { $data = file_get_contents(dirname(__FILE__) . '/../_files/Books/books.xsd'); $expectedTypeList = array(); $expectedType1 = new PiBX_AST_Type('Collection'); $expectedType1->setAsRoot(); $expectedType1->setAttributeCount(1); $expectedType1->setNamespaces(array('xs' => 'http://www.w3.org/2001/XMLSchema')); $ta = new PiBX_AST_TypeAttribute('books'); $c = new PiBX_AST_Collection(); $ci = new PiBX_AST_CollectionItem('book'); $ci->setType('bookType'); $expectedType1->add($ta); $ta->add($c); $c->add($ci); $expectedTypeList[] = $expectedType1; $expectedType2 = new PiBX_AST_Type('bookType'); $expectedType2->setAttributeCount(8); $expectedType2->add(new PiBX_AST_TypeAttribute('name', 'string')); $expectedType2->add(new PiBX_AST_TypeAttribute('ISBN', 'long')); $expectedType2->add(new PiBX_AST_TypeAttribute('price', 'string')); $ta = new PiBX_AST_TypeAttribute('authors'); $c = new PiBX_AST_Collection(); $ci = new PiBX_AST_CollectionItem('authorName', 'string'); $c->add($ci); $ta->add($c); $expectedType2->add($ta); $expectedType2->add(new PiBX_AST_TypeAttribute('description', 'string')); $ta = new PiBX_AST_TypeAttribute('promotion'); $s = new PiBX_AST_Structure(); $s->setStructureType(PiBX_AST_StructureType::CHOICE()); $s->add(new PiBX_AST_StructureElement('Discount', 'string')); $s->add(new PiBX_AST_StructureElement('None', 'string')); $ta->add($s); $expectedType2->add($ta); $expectedType2->add(new PiBX_AST_TypeAttribute('publicationDate', 'date')); $ta = new PiBX_AST_TypeAttribute('bookCategory'); $e = new PiBX_AST_Enumeration(); $e->add(new PiBX_AST_EnumerationValue('magazine', 'string')); $e->add($ev = new PiBX_AST_EnumerationValue('novel', 'string')); $e->add($ev = new PiBX_AST_EnumerationValue('fiction', 'string')); $e->add($ev = new PiBX_AST_EnumerationValue('other', 'string')); $ta->add($e); $expectedType2->add($ta); $ta = new PiBX_AST_TypeAttribute('itemId', 'string'); $ta->setStyle('attribute'); $expectedType2->add($ta); $expectedTypeList[] = $expectedType2; $enumeration = new PiBX_AST_Enumeration(); $enumeration->add(new PiBX_AST_EnumerationValue('magazine', 'string')); $enumeration->add(new PiBX_AST_EnumerationValue('novel', 'string')); $enumeration->add(new PiBX_AST_EnumerationValue('fiction', 'string')); $enumeration->add(new PiBX_AST_EnumerationValue('other', 'string')); $expectedType3 = new PiBX_AST_Type('bookCategoryType'); $expectedType3->add($enumeration); $expectedTypeList[] = $expectedType3; $schema = simplexml_load_string($data); $parser = new PiBX_CodeGen_SchemaParser(); $parser->setSchema($schema); $tree = $parser->parse(); $creator = new PiBX_CodeGen_ASTCreator(new PiBX_CodeGen_TypeUsage()); $tree->accept($creator); $typeList = $creator->getTypeList(); $this->assertEquals(3, count($typeList)); $this->assertEquals($expectedType1, $typeList[0]); $this->assertEquals($expectedType2, $typeList[1]); $this->assertEquals($expectedType3, $typeList[2]); }
private function marshalTypeAttribute($object, PiBX_AST_TypeAttribute $ast) { if ($ast->getStyle() == 'element') { $getter = $ast->getGetMethod(); $value = $object->{$getter}(); $newNode = $this->dom->createTextNode($value); $this->currentDomNode->appendChild($newNode); } elseif ($ast->getStyle() == 'attribute') { $getter = $ast->getGetMethod(); $name = $ast->getName(); $value = $object->{$getter}(); if ($value != '') { // TODO check for "optional" attribute in binding. $this->parentDomNode->setAttribute($name, $value); } // in marshalObject() a child is added everytime. // no matter what type it is ("attribute" or "element"), // so we can just remove it here $this->parentDomNode->removeChild($this->currentDomNode); } else { throw new RuntimeException('Invalid TypeAttribute style "' . $ast->getStyle() . '"'); } }