Xsd.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <?php
  2. Lib::loadClass('ApiDataSourceTodo');// TODO: @see Entity/Source/Mysql from feature-schema-install
  3. Lib::loadClass('Data_Source');
  4. Lib::loadClass('ApiRouteBase');
  5. class Api_Xsd extends ApiRouteBase {
  6. public $_apiUser;
  7. public $_dataSourceName;
  8. public $_tblName;
  9. public $_tblSchema;
  10. public function execute($request) {
  11. if (!$this->_apiUser->isAdmin()) {
  12. throw new HttpException("Forbidden", 403);
  13. }
  14. session_write_close();
  15. IF(V::get('DBG','',$_GET)){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">request->segments (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($request->segments);echo'</pre>';}
  16. if (empty($request->segments) || !is_array($request->segments)) return;
  17. if (count($request->segments) < 1) {
  18. throw new HttpException("Data source and table name not specified", 400);
  19. }
  20. $this->_dataSourceName = array_shift($request->segments);
  21. if ('default_db' == $this->_dataSourceName) {
  22. $limit = 1000;
  23. $rawListAllTables = DB::getPDO()->fetchAll(" show full tables where Table_type = 'BASE TABLE' ");
  24. $listAllTableNames = array_map(function ($item) {
  25. $values = array_values($item);
  26. return $values[0];
  27. }, $rawListAllTables);
  28. $listAllowedTableNames = array_filter($listAllTableNames, function ($tableName) {
  29. if (false !== strpos($tableName, '@')) return false;
  30. if (false !== strpos($tableName, '#')) return false;
  31. if ('_HIST' === substr($tableName, -1 * strlen('_HIST'))) return false;
  32. if ('DEALS_TABLE_2015_03_17_zest_dla_zubryka' === $tableName) return false; // fields name 'grup_concat(...'
  33. return true;
  34. });
  35. $tbls = [];
  36. $tableNames = array_slice($listAllowedTableNames, 0, $limit);
  37. foreach ($tableNames as $tblName) {
  38. $ds = new Data_Source();
  39. $ds->set_table($tblName);
  40. $ds->get_cols();
  41. $tbls[$tblName] = $ds;
  42. if (--$limit < 0) break;
  43. }
  44. $xml = <<<XMLEOF
  45. <?xml version="1.0"?>
  46. <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:{$this->_dataSourceName}="http://biuro.biall-net.pl/xmlschema_procesy5/{$this->_dataSourceName}" targetNamespace="http://biuro.biall-net.pl/xmlschema_procesy5/{$this->_dataSourceName}">
  47. XMLEOF;
  48. foreach ($tbls as $tblName => $ds) {
  49. $xmlFields = array();
  50. $tblFields = $ds->_col_types;
  51. $xmlTableNamedSimpleTypes = array();
  52. foreach ($tblFields as $fldName => $colType) {
  53. $minOccurs = 0;
  54. $maxOccurs = 1;
  55. $colDefault = null;
  56. $xsdType = 'string';
  57. //$xsdType = 'token';
  58. //$xsdType = 'integer';
  59. //$xsdType = 'double';
  60. $xsdRestrictions = array();
  61. if (false !== strpos($colType, ';')) {
  62. $colType = explode(';', $colType, 2);
  63. $colDefault = array_pop($colType);
  64. $colType = array_shift($colType);
  65. }
  66. //$xsdRestrictions[] = '<xs:enumeration value="WAITING"/>';
  67. if ($this->isIntegerField($colType)) {
  68. $xsdType = 'integer';
  69. }
  70. else if ($this->isDecimalField($colType)) {
  71. $xsdType = 'double';
  72. }
  73. else if ($this->isStringField($colType)) {
  74. $xsdType = 'string';
  75. $maxLength = (int)str_replace(array(' ','(',')'), '', substr($colType, strpos($colType, '(') + 1, -1));
  76. if ($maxLength > 0) {
  77. $xsdRestrictions[] = '<xs:maxLength value="' . $maxLength . '"/>';
  78. }
  79. }
  80. else if ($this->isTextField($colType)) {
  81. $xsdType = 'string';
  82. }
  83. else if ($this->isDateField($colType)) {
  84. $xsdType = 'token';
  85. $xsdDatePattern = '[0-9]{4}-[0-9]{2}-[0-9]{2}';
  86. $xsdRestrictions[] = '<xs:pattern value="' . $xsdDatePattern . '"/>';
  87. }
  88. else if ($this->isDateTimeField($colType)) {
  89. $xsdType = 'token';
  90. $xsdDatePattern = '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}';
  91. $xsdRestrictions[] = '<xs:pattern value="' . $xsdDatePattern . '"/>';
  92. }
  93. else if (substr($colType, 0, 4) == 'year') {
  94. $xsdType = 'token';
  95. $xsdDatePattern = '[0-9]{4}';
  96. $xsdRestrictions[] = '<xs:pattern value="' . $xsdDatePattern . '"/>';
  97. }
  98. else if (substr($colType, 0, 4) == 'enum') {
  99. $xsdType = 'string';
  100. $values = explode(',', str_replace(array('(',')',"'",'"'), '', substr($colType, 5)));
  101. foreach ($values as $val) {
  102. $xsdRestrictions[] = '<xs:enumeration value="' . $val . '"/>';
  103. }
  104. }
  105. else if ('polygon' == $colType) {
  106. $xsdType = 'string';
  107. }// Wielokąt
  108. else if ('multipolygon' == $colType) {
  109. $xsdType = 'string';
  110. }// Zbiór wielokątów
  111. else if ('linestring' == $colType) {
  112. $xsdType = 'string';
  113. }// Krzywa z interpolacji liniowej pomiędzy punktami
  114. else if ('point' == $colType) {
  115. $xsdType = 'string';
  116. }// Punkt w przestrzeni 2-wymiarowej
  117. else if ('geometry' == $colType) {
  118. $xsdType = 'string';
  119. }// Typy, które mogą przechowywać geometrię dowolnego typu
  120. else if ('multipoint' == $colType) {
  121. $xsdType = 'string';
  122. }// Zbiór punktów
  123. else if ('multilinestring' == $colType) {
  124. $xsdType = 'string';
  125. }// Zbiór krzywych z interpolacji liniowej pomiędzy punktami
  126. else if ('geometrycollection' == $colType) {
  127. $xsdType = 'string';
  128. }// Zbiór obiektów geometrycznych dowolnego typu
  129. else if ('timestamp' == substr($colType, 0, 9)) {
  130. $xsdType = 'string';
  131. }
  132. else if ('time' == substr($colType, 0, 4)) {
  133. $xsdType = 'token';
  134. $xsdDatePattern = '[0-9]{2}:[0-9]{2}:[0-9]{2}';
  135. $xsdRestrictions[] = '<xs:pattern value="' . $xsdDatePattern . '"/>';
  136. }
  137. else if ('binary' == substr($colType, 0, 6)
  138. || 'varbinary' == substr($colType, 0, 9)) {
  139. $xsdType = 'hexBinary';
  140. }
  141. else if ('blob' == substr($colType, 0, 4)
  142. || 'longblob' == substr($colType, 0, 8)
  143. || 'mediumblob' == substr($colType, 0, 10)
  144. || 'tinyblob' == substr($colType, 0, 8)) {
  145. $xsdType = 'hexBinary';
  146. }
  147. else if (substr($colType, 0, 3) == 'set') {
  148. $xsdType = 'string';
  149. $values = explode(',', str_replace(array('(',')',"'",'"'), '', substr($colType, 4)));
  150. foreach ($values as $val) {
  151. $xsdRestrictions[] = '<xs:enumeration value="' . $val . '"/>';
  152. }
  153. }
  154. else {
  155. $xsdType = 'unknown-Type-'.$colType.'';
  156. }
  157. $xmlFld = '';
  158. $xmlFieldTypeName = "{$tblName}__{$fldName}";
  159. $xmlFld .= '<xs:element minOccurs="' . $minOccurs . '" maxOccurs="' . $maxOccurs . '" name="' . $fldName . '" type="' . "{$this->_dataSourceName}:{$xmlFieldTypeName}" . '">';
  160. {
  161. $xmlNamedSimpleType = '';
  162. $xmlNamedSimpleType .= "\n" . '<xs:simpleType name="' . $xmlFieldTypeName . '">';
  163. if (!empty($xsdRestrictions)) {
  164. $xmlNamedSimpleType .= "\n\t" . '<xs:restriction base="xs:' . $xsdType . '">';
  165. $xmlNamedSimpleType .= "\n\t\t" . implode("\n\t\t", $xsdRestrictions);
  166. $xmlNamedSimpleType .= "\n\t" . '</xs:restriction>';
  167. } else {
  168. $xmlNamedSimpleType .= "\n\t" . '<xs:restriction base="xs:' . $xsdType . '"/>';
  169. }
  170. $xmlNamedSimpleType .= "\n" . '</xs:simpleType>';
  171. $xmlTableNamedSimpleTypes[] = $xmlNamedSimpleType;
  172. }
  173. $xmlFld .= "\n\t\t\t" . '</xs:element>';
  174. $xmlFields[] = $xmlFld;
  175. }
  176. $xmlFields = implode("\n\t\t\t", $xmlFields);
  177. $xmlTableNamedSimpleTypes = implode("\n", $xmlTableNamedSimpleTypes);
  178. $xml .= <<<XMLEOF
  179. <xs:element name="{$tblName}" type="{$this->_dataSourceName}:{$tblName}"/>
  180. <xs:complexType name="{$tblName}">
  181. <xs:sequence>
  182. {$xmlFields}
  183. </xs:sequence>
  184. </xs:complexType>
  185. {$xmlTableNamedSimpleTypes}
  186. XMLEOF;
  187. }
  188. $xml .= <<<XMLEOF
  189. </xs:schema>
  190. XMLEOF;
  191. header('Content-Type: text/xml; charset=utf-8');
  192. echo $xml;
  193. exit;
  194. //echo'<pre>';print_r($tbls);echo'</pre>';
  195. }
  196. // return document tree - array of arrays
  197. }
  198. // FROM TableAcl {
  199. public function isIntegerField($type) {
  200. if (substr($type, 0, 3) == 'int'
  201. || substr($type, 0, 7) == 'tinyint'
  202. || substr($type, 0, 8) == 'smallint'
  203. || substr($type, 0, 9) == 'mediumint'
  204. || substr($type, 0, 6) == 'bigint'
  205. ) {
  206. return true;
  207. }
  208. return false;
  209. }
  210. public function isDecimalField($type) {
  211. if (substr($type, 0, 7) == 'decimal'
  212. || substr($type, 0, 7) == 'numeric'
  213. || substr($type, 0, 6) == 'double'
  214. || substr($type, 0, 5) == 'float'
  215. || substr($type, 0, 4) == 'real'
  216. ) {
  217. return true;
  218. }
  219. return false;
  220. }
  221. public function isDateField($type) {
  222. if (substr($type, 0, 4) == 'date' && substr($type, 0, 8) != 'datetime') {
  223. return true;
  224. }
  225. return false;
  226. }
  227. public function isDateTimeField($type) {
  228. if (substr($type, 0, 8) == 'datetime') {
  229. return true;
  230. }
  231. return false;
  232. }
  233. public function isStringField($type) {
  234. if (substr($type, 0, 7) == 'varchar'
  235. || substr($type, 0, 4) == 'char'
  236. ) {
  237. return true;
  238. }
  239. return false;
  240. }
  241. public function isTextField($type) {
  242. if (substr($type, 0, 4) == 'text'
  243. || substr($type, 0, 8) == 'tinytext'
  244. || substr($type, 0, 10) == 'mediumtext'
  245. || substr($type, 0, 8) == 'longtext'
  246. ) {
  247. return true;
  248. }
  249. return false;
  250. }
  251. // FROM } TableAcl
  252. private function getDataSource() {
  253. if (!$this->_dataSource) {
  254. // TODO: get data source from Factory
  255. {
  256. if ('default_db' == $this->_dataSourceName) {
  257. $this->_dataSource = new ApiDataSourceTodo($this->_dataSourceName);
  258. $this->_dataSource->setTable($this->_tblName);
  259. }
  260. else if ('931' == $this->_dataSourceName) {
  261. $this->_dataSource = new ApiDataSourceTodo($this->_dataSourceName);
  262. $this->_dataSource->setTable($this->_tblName);
  263. }
  264. }
  265. }
  266. return $this->_dataSource;
  267. }
  268. }