File modules/template_engine/components/XSDGenerator.class.php
Last commit: Sat Oct 17 01:37:53 2026 +0200 Jan Dankert Refactoring: The TemplateCompile and XSDGenerator are now classes.
1 <?php 2 /** 3 * Using the Component classes and generating a XSD-File. 4 */ 5 6 namespace template_engine\components; 7 8 #use cms\base\Startup; 9 use ReflectionClass; 10 use ReflectionNamedType; 11 use util\FileUtils; 12 13 #Startup::initialize(); 14 15 class XSDGenerator { 16 17 public function generate(): void 18 { 19 20 require(__DIR__.'/../../util/FileUtils.class.php'); 21 22 // Baseclass of all components. 23 require('html/Component.class.php'); 24 require('html/HtmlComponent.class.php'); 25 require('html/FieldComponent.class.php'); 26 27 echo "XSD Generator\n\n"; 28 29 $folder = FileUtils::readDir(__DIR__ . '/html'); 30 31 $componentsFile = @fopen(__DIR__ . '/components.ini', 'w'); 32 $xsdFile = @fopen(__DIR__ . '/template.xsd', 'w'); 33 34 fwrite($componentsFile, '# generated by XSDGenerator. do not change manually.' . "\n"); 35 fwrite($xsdFile, '<?xml version="1.0" encoding="utf-8"?> 36 <xsd:schema xmlns="http://www.openrat.de/template" 37 targetNamespace="http://www.openrat.de/template" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 38 elementFormDefault="qualified" attributeFormDefault="unqualified">' . "\n". 39 '<!-- generated by XSDGenerator. do not change manually -->'."\n"); 40 41 // Only directories 42 $folder = array_filter( $folder,function($name) { 43 return substr($name,0,10) == 'component_'; 44 } ); 45 // Cut 'component_' from directory names 46 $folder = array_map( function($name) { 47 return substr($name,10); 48 }, $folder ); 49 50 // Sort... 51 asort($folder); 52 53 foreach ($folder as $componentName) { 54 55 echo 'Working on component: ' . $componentName . "\n"; 56 $className = 'template_engine\\components\\html\\component_'.$componentName.'\\' . ucfirst($componentName) . 'Component'; 57 $componentClass = new ReflectionClass($className); 58 fwrite($componentsFile, $componentName . " = \n"); 59 60 $comment = $this->clearDocComment($componentClass->getDocComment()); 61 fwrite($xsdFile, '<xsd:element name="' . $componentName . '" type="' . $componentName . 'Type">' 62 .'<xsd:annotation><xsd:documentation xml:lang="en">'.$comment.'</xsd:documentation></xsd:annotation>' 63 .'</xsd:element>' 64 .'<xsd:complexType name="' . $componentName . 'Type">'."\n"); 65 66 67 // Allow HTML children 68 //fwrite($xsdFile, '<xsd:openContent mode="interleave">'. 69 // '<xsd:any namespace="http://www.w3.org/1999/xhtml" />'. 70 // '</xsd:openContent>'); 71 72 // Allowed Child-Elements (all) 73 fwrite($xsdFile, '<xsd:choice maxOccurs="unbounded" minOccurs="0">'); 74 foreach ($folder as $cName) { 75 fwrite($xsdFile, '<xsd:element ref="' . $cName . '" maxOccurs="unbounded" minOccurs="0" />'); 76 } 77 78 fwrite($xsdFile,'<xsd:any namespace="http://www.w3.org/1999/xhtml" />' ); 79 80 fwrite($xsdFile, '</xsd:choice>'."\n"); 81 82 83 foreach ($componentClass->getProperties() as $reflectionProperty) { 84 if ( ! $reflectionProperty->isPublic() ) 85 continue; 86 87 $name = $reflectionProperty->getName(); 88 $type = $reflectionProperty->getType(); 89 // 1. Prüfen, ob überhaupt ein Typ deklariert wurde 90 if ($type !== null) { 91 // 2. Handelt es sich um einen einfachen, benannten Typ? 92 if ($type instanceof ReflectionNamedType) { 93 $typeName = $type->getName(); // Liefert "int", "string" oder "bool" 94 95 switch ($typeName) { 96 case 'int': 97 $xsdtype = 'xsd:int'; 98 break; 99 case 'string': 100 $xsdtype = 'xsd:string'; 101 break; 102 case 'bool': 103 $xsdtype = 'xsd:boolean'; 104 break; 105 default: 106 // "Anderer Typ oder Klasse: " . $typeName; 107 $xsdtype = 'xsd:string'; 108 } 109 } 110 else 111 $xsdtype = 'xsd:string'; 112 } 113 else 114 $xsdtype = 'xsd:string'; 115 116 $commentAttr = $reflectionProperty->getAttributes(\template_engine\components\XsdComment::class); 117 118 if (!empty($commentAttr) ) { 119 // Wenn ja, mappen wir jedes Element im Array rekursiv 120 $comment = $commentAttr[0]->newInstance()->comment; 121 } else { 122 $comment = $this->clearDocComment($reflectionProperty->getDocComment()); 123 if ( !$comment ) 124 $comment = 'Attribute '.$reflectionProperty->getName(); 125 } 126 $comment .= ' (Default: '.$reflectionProperty->getDefaultValue().')'; 127 fwrite($xsdFile, '<xsd:attribute name="' . $name . '" type="' . $xsdtype . '">'); 128 fwrite($xsdFile,'<xsd:annotation><xsd:documentation xml:lang="en">'.$comment.'</xsd:documentation></xsd:annotation>'); 129 fwrite($xsdFile, '</xsd:attribute>'); 130 } 131 132 133 fwrite($xsdFile, '</xsd:complexType>'."\n"); 134 135 } 136 137 fwrite($xsdFile, '</xsd:schema>'); 138 139 fclose($xsdFile); 140 fclose($componentsFile); 141 142 echo "Finished.\n"; 143 } 144 145 function clearDocComment(string|null $comment):string { 146 147 if ( !$comment ) return ''; 148 149 $comment = str_replace('/*','',$comment); 150 $comment = str_replace('*/','',$comment); 151 $comment = str_replace('*','',$comment); 152 $comment = str_replace("\n",' ',$comment); 153 154 $idx = strpos($comment,'@'); 155 if ( $idx !== false ) 156 $comment = substr( $comment,0,$idx-1); 157 158 return trim($comment); 159 } 160 }
Downloadmodules/template_engine/components/XSDGenerator.class.php
History Sat, 17 Oct 2026 01:37:53 +0200 Jan Dankert Refactoring: The TemplateCompile and XSDGenerator are now classes.