TestXsd.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. <?php
  2. Lib::loadClass('RouteBase');
  3. class Route_Storage_TestXsd extends RouteBase {
  4. public function defaultAction() {
  5. $idStorage = V::get('idStorage', 0, $_REQUEST, 'int');
  6. $storage = DB::getStorage($idStorage);
  7. $tableRealList = $storage->getTableList();
  8. $srvName = $_SERVER['SERVER_NAME'];
  9. $storageZasobId = $storage->getZasobId();
  10. $objNs = "p5_{$storageZasobId}_{$tblName}";
  11. $objNsUri = "https://biuro.biall-net.pl/api/{$storageZasobId}/{$tblName}";
  12. $p5TypePrefix = "p5Type";
  13. $p5TypeNsUri = "http://biuro.biall-net.pl/p5/schema/types";
  14. $p5TypeNsLocation = "http://biuro.biall-net.pl/p5/schema/types.xsd";
  15. header('Content-type: text/plain; charset=utf-8');// TODO: test
  16. //header('Content-type: application/xml; charset=utf-8');
  17. $xmlWriter = new XMLWriter();
  18. $xmlWriter->openUri('php://output');
  19. $xmlWriter->setIndent(true);
  20. if (!$xmlWriter) throw new HttpException("Error no XMLWriter", 404);
  21. $xmlWriter->startDocument('1.0', 'UTF-8');
  22. $xmlWriter->startElement('xs:schema');
  23. $xmlWriter->writeAttribute('xmlns:xs', 'http://www.w3.org/2001/XMLSchema');
  24. $xmlWriter->writeAttribute('xmlns:vc', 'http://www.w3.org/2007/XMLSchema-versioning');
  25. $xmlWriter->writeAttribute('xmlns:system_cache__appinfo', 'http://biuro.biall-net.pl/xmlschema_procesy5/default_db_xml_cache/appinfo.xsd');
  26. $xmlWriter->writeAttribute("xmlns:{$p5TypePrefix}", $p5TypeNsUri);
  27. if(DB::getPDO()->getZasobId() === $idStorage) {} else {
  28. $xmlWriter->writeAttribute('xmlns:p5_zasob_'.$idStorage, $objNsUri ); //brakuje deklaracji xmlns dla innego zasobu
  29. }
  30. $xmlWriter->writeAttribute('elementFormDefault', 'qualified');
  31. $xmlWriter->writeAttribute('targetNamespace', $objNsUri);
  32. $xmlWriter->writeAttribute('vc:minVersion', '1.1');
  33. $xmlWriter->startElement('xs:import');
  34. $xmlWriter->writeAttribute('namespace', $p5TypeNsUri);
  35. $xmlWriter->writeAttribute('schemaLocation', $p5TypeNsLocation);
  36. $xmlWriter->endElement();// xs:import
  37. foreach ($tableRealList as $tbl) {
  38. $tblName = $tbl['table_name'];
  39. $this->tableXsdViewXmlWriter($xmlWriter, $idStorage, $tblName);
  40. }
  41. $xmlWriter->endElement();// xs:schema
  42. $xmlWriter->endDocument();
  43. }
  44. public function tableXsdAction() {
  45. $idStorage = V::get('idStorage', '', $_GET);
  46. $tblName = V::get('table', '', $_GET, 'word');
  47. if (empty($tblName)) die("Wrong table name");
  48. header('Content-type: text/plain; charset=utf-8');// TODO: test
  49. $storage = DB::getStorage($idStorage);
  50. $storageZasobId = $storage->getZasobId();
  51. $objNs = "p5_{$storageZasobId}_{$tblName}";
  52. $objNsUri = "https://biuro.biall-net.pl/api/{$storageZasobId}/{$tblName}";
  53. $p5TypePrefix = "p5Type";
  54. $p5TypeNsUri = "http://biuro.biall-net.pl/p5/schema/types";
  55. $p5TypeNsLocation = "http://biuro.biall-net.pl/p5/schema/types.xsd";
  56. //header('Content-type: application/xml; charset=utf-8');
  57. $xmlWriter = new XMLWriter();
  58. $xmlWriter->openUri('php://output');
  59. $xmlWriter->setIndent(true);
  60. if (!$xmlWriter) throw new HttpException("Error no XMLWriter", 404);
  61. $xmlWriter->startDocument('1.0', 'UTF-8');
  62. $xmlWriter->startElement('xs:schema');
  63. $xmlWriter->writeAttribute('xmlns:xs', 'http://www.w3.org/2001/XMLSchema');
  64. $xmlWriter->writeAttribute('xmlns:vc', 'http://www.w3.org/2007/XMLSchema-versioning');
  65. $xmlWriter->writeAttribute("xmlns:{$p5TypePrefix}", $p5TypeNsUri);
  66. $xmlWriter->writeAttribute('elementFormDefault', 'qualified');
  67. $xmlWriter->writeAttribute('targetNamespace', $objNsUri);
  68. $xmlWriter->writeAttribute('vc:minVersion', '1.1');
  69. $xmlWriter->startElement('xs:import');
  70. $xmlWriter->writeAttribute('namespace', $p5TypeNsUri);
  71. $xmlWriter->writeAttribute('schemaLocation', $p5TypeNsLocation);
  72. $xmlWriter->endElement();// xs:import
  73. $this->tableXsdViewXmlWriter($xmlWriter, $idStorage, $tblName);
  74. $xmlWriter->endElement();// xs:schema
  75. $xmlWriter->endDocument();
  76. }
  77. public function tableXsdViewXmlWriter(&$xmlWriter, $idStorage, $tblName) {
  78. $storage = DB::getStorage($idStorage);
  79. $schema = Schema_TableFactory::build($tblName, $idStorage, $_SERVER['SERVER_NAME']);
  80. $struct = $schema->getStruct();
  81. DBG::_('DBG', '>1', "struct", $struct, __CLASS__, __FUNCTION__, __LINE__);
  82. $typeName = "{$tblName}"; //.Type is not like others xsd. objects
  83. $xmlWriter->startElement('xs:complexType');
  84. $xmlWriter->writeAttribute('name', $typeName);
  85. $xmlWriter->startElement('xs:sequence');
  86. $foreignKeys = [];
  87. {
  88. $dbName = DB::getPDO($idStorage)->getDatabaseName();
  89. if ('mysql' === DB::getPDO($idStorage)->getType()) {
  90. $foreignKeys = DB::getPDO($idStorage)->fetchAll("
  91. SELECT i.TABLE_SCHEMA, i.TABLE_NAME, i.CONSTRAINT_TYPE, i.CONSTRAINT_NAME, k.COLUMN_NAME, k.REFERENCED_TABLE_NAME, k.REFERENCED_COLUMN_NAME
  92. FROM information_schema.TABLE_CONSTRAINTS i
  93. LEFT JOIN information_schema.KEY_COLUMN_USAGE k ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME
  94. WHERE i.TABLE_SCHEMA = :db_name
  95. and i.TABLE_NAME = :tbl_name
  96. and i.CONSTRAINT_TYPE = 'FOREIGN KEY'
  97. ORDER BY i.TABLE_NAME
  98. ", [
  99. ':db_name' => $dbName,
  100. ':tbl_name' => $tblName,
  101. ]);
  102. // if ('CRM_WSKAZNIK' === $tblName) { // @example: CRM_WSKAZNIK.ID_ZASOB => CRM_LISTA_ZASOBOW.ID
  103. // $foreignKeys = [
  104. // [ 'TABLE_SCHEMA' => "SES_USERS2"
  105. // , 'TABLE_NAME' => "CRM_WSKAZNIK"
  106. // , 'CONSTRAINT_TYPE' => "FOREIGN KEY"
  107. // , 'CONSTRAINT_NAME' => "zasob"
  108. // , 'COLUMN_NAME' => "ID_ZASOB"
  109. // , 'REFERENCED_TABLE_NAME' => "CRM_LISTA_ZASOBOW"
  110. // , 'REFERENCED_COLUMN_NAME' => "ID"
  111. // ]
  112. // ];
  113. // }
  114. // $xmlWriter->writeComment("\$foreignKeys: " . var_export($foreignKeys, true));
  115. // TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_TYPE, CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
  116. // * * FOREIGN KEY * * * *
  117. }
  118. }
  119. foreach ($struct as $field) {
  120. $xmlWriter->startElement('xs:element');
  121. $xmlWriter->writeAttribute('name', $field['name']);
  122. $xmlWriter->writeAttribute('minOccurs', 0);// TODO: set minOccurs by default, etc.
  123. if ($field['is_nullable']) $xmlWriter->writeAttribute('nillable', 'true');
  124. if (null !== $field['default_value']) {
  125. $xmlWriter->writeAttribute('default', $field['default_value']);
  126. } else if (null === $field['default_value'] && $field['is_nullable']) {
  127. $xmlWriter->writeAttribute('default', $field['default_value']);
  128. } else {
  129. // TODO: Schema BUG?
  130. }
  131. if (empty($field['p5_restrictions'])) {
  132. $xmlWriter->writeAttribute('type', "p5Type:{$field['p5_type']}");
  133. } else {
  134. $xmlWriter->startElement('xs:simpleType');
  135. $xmlWriter->writeAttribute('base', "p5Type:{$field['p5_type']}");
  136. $xmlWriter->startElement('xs:restriction');
  137. if (!empty($field['p5_restrictions']['enumeration'])) {
  138. foreach ($field['p5_restrictions']['enumeration'] as $enumValue) {
  139. $xmlWriter->startElement('xs:enumeration');
  140. $xmlWriter->writeAttribute('value', $enumValue);
  141. $xmlWriter->endElement();// xs:enumeration
  142. }
  143. } else {
  144. // TODO: another restrictions...
  145. }
  146. $xmlWriter->endElement();// xs:restriction
  147. $xmlWriter->endElement();// xs:simpleType
  148. }
  149. $xmlWriter->endElement();// xs:element
  150. }
  151. if (!empty($foreignKeys)) {
  152. foreach ($foreignKeys as $key) {
  153. $xmlWriter->startElement('xs:element');
  154. $xmlWriter->writeAttribute('name', $key['REFERENCED_COLUMN_NAME']); //todo may not be unique - to be set table__x3A__name
  155. $refPrefix = (DB::getPDO()->getZasobId() === $idStorage) ? 'p5_default_db' : "p5_zasob_{$idStorage}";
  156. $xmlWriter->writeAttribute('type', "{$refPrefix}:{$key['REFERENCED_TABLE_NAME']}"); //it is better to show it as type to be than translated to references than having fake ref
  157. $xmlWriter->startElement('xs:annotation');
  158. $xmlWriter->startElement('xs:appinfo');
  159. $xmlWriter->startElement('system_cache__appinfo:flat_relation_cache');
  160. $xmlWriter->writeAttribute("system_cache__appinfo:name", $key['COLUMN_NAME']);
  161. $xmlWriter->writeAttribute("system_cache__appinfo:xpath", "{$refPrefix}:{$key['REFERENCED_TABLE_NAME']}/{$key['REFERENCED_COLUMN_NAME']}");
  162. $xmlWriter->endElement();// system_cache__appinfo:flat_relation_cache
  163. $xmlWriter->endElement();// xs:appinfo
  164. $xmlWriter->endElement();// xs:annotation
  165. $xmlWriter->endElement();// xs:element
  166. }
  167. }
  168. $xmlWriter->endElement();// xs:sequence
  169. $xmlWriter->endElement();// xs:complexType
  170. return;
  171. // <xs:element maxOccurs="1" minOccurs="0" name="{$fldName}" nillable="true" type="xs:integer"/>
  172. $pKeyField = 'ID';//$storageObject->getPrimaryKeyFieldName();
  173. //DBG::_(true, true, "struct", $struct, __CLASS__, __FUNCTION__, __LINE__);
  174. foreach ($struct as $field) {
  175. $fldName = $vField->getName();
  176. $fldType = $vField->getType();
  177. $xsdType = $fldType->getTypeForXsd();
  178. if ($fldType->hasDefault()) {
  179. $fldDefault = $fldType->getDefault();
  180. if (!empty($fldDefault) || '0' === $fldDefault) {
  181. $elNode->setAttribute('default', $fldDefault);
  182. }
  183. }
  184. $fldRestrictions = $fldType->getRestrictions();
  185. if (empty($fldRestrictions)) {
  186. $elNode->setAttribute('type', "{$p5TypePrefix}:{$xsdType}");
  187. } else {
  188. $sType = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:simpleType');
  189. $elNode->appendChild($sType);
  190. $sTypeRes = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:restriction');
  191. $sType->appendChild($sTypeRes);
  192. $sTypeRes->setAttribute('base', "{$p5TypePrefix}:{$xsdType}");
  193. $enumList = $fldType->getEnumeration();
  194. if (empty($enumList)) {
  195. foreach ($fldRestrictions as $restricionName => $restrictionValue) {
  196. if ('maxLength' == $restricionName) {
  197. $sTypeResMaxLength = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:maxLength');
  198. $sTypeRes->appendChild($sTypeResMaxLength);
  199. $sTypeResMaxLength->setAttribute('value', $restrictionValue);
  200. } else if ('minLength' == $restricionName) {
  201. $sTypeResMinLength = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:minLength');
  202. $sTypeRes->appendChild($sTypeResMinLength);
  203. $sTypeResMinLength->setAttribute('value', $restrictionValue);
  204. } else if ('pattern' == $restricionName) {
  205. $sTypeResPattern = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:pattern');
  206. $sTypeRes->appendChild($sTypeResPattern);
  207. $sTypeResPattern->setAttribute('value', $restrictionValue);
  208. } else if ('fractionDigits' == $restricionName) {
  209. $sTypeResFractionDigits = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:fractionDigits');
  210. $sTypeRes->appendChild($sTypeResFractionDigits);
  211. $sTypeResFractionDigits->setAttribute('value', $restrictionValue);
  212. } else if ('totalDigits' == $restricionName) {
  213. $sTypeResTotalDigits = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:totalDigits');
  214. $sTypeRes->appendChild($sTypeResTotalDigits);
  215. $sTypeResTotalDigits->setAttribute('value', $restrictionValue);
  216. } else if ('maxExclusive' == $restricionName) {
  217. $sTypeResMaxExclusive = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:maxExclusive');
  218. $sTypeRes->appendChild($sTypeResMaxExclusive);
  219. $sTypeResMaxExclusive->setAttribute('value', $restrictionValue);
  220. } else if ('minExclusive' == $restricionName) {
  221. $sTypeResMinExclusive = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:minExclusive');
  222. $sTypeRes->appendChild($sTypeResMinExclusive);
  223. $sTypeResMinExclusive->setAttribute('value', $restrictionValue);
  224. } else if ('maxInclusive' == $restricionName) {
  225. $sTypeResMaxInclusive = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:maxInclusive');
  226. $sTypeRes->appendChild($sTypeResMaxInclusive);
  227. $sTypeResMaxInclusive->setAttribute('value', $restrictionValue);
  228. } else if ('minInclusive' == $restricionName) {
  229. $sTypeResMinInclusive = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:minInclusive');
  230. $sTypeRes->appendChild($sTypeResMinInclusive);
  231. $sTypeResMinInclusive->setAttribute('value', $restrictionValue);
  232. }
  233. /* TODO: xsd restrictions:
  234. enumeration Defines a list of acceptable values
  235. fractionDigits Specifies the maximum number of decimal places allowed. Must be equal to or greater than zero
  236. length Specifies the exact number of characters or list items allowed. Must be equal to or greater than zero
  237. maxExclusive Specifies the upper bounds for numeric values (the value must be less than this value)
  238. maxInclusive Specifies the upper bounds for numeric values (the value must be less than or equal to this value)
  239. maxLength Specifies the maximum number of characters or list items allowed. Must be equal to or greater than zero
  240. minExclusive Specifies the lower bounds for numeric values (the value must be greater than this value)
  241. minInclusive Specifies the lower bounds for numeric values (the value must be greater than or equal to this value)
  242. minLength Specifies the minimum number of characters or list items allowed. Must be equal to or greater than zero
  243. pattern Defines the exact sequence of characters that are acceptable
  244. totalDigits Specifies the exact number of digits allowed. Must be greater than zero
  245. whiteSpace Specifies how white space (line feeds, tabs, spaces, and carriage returns) is handled
  246. */
  247. }
  248. } else {
  249. foreach ($enumList as $enumValue) {
  250. $sTypeResEnum = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:enumeration');
  251. $sTypeRes->appendChild($sTypeResEnum);
  252. $sTypeResEnum->setAttribute('value', $enumValue);
  253. }
  254. }
  255. }
  256. }
  257. $elNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xs:element');
  258. $rootNode->appendChild($elNode);
  259. $elNode->setAttribute('name', $tblName);
  260. $elNode->setAttribute('type', "{$objNs}:{$typeName}");
  261. header('Content-type: application/xml');
  262. echo $dom->saveXML();
  263. exit;
  264. }
  265. }