SchemaHelper.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?php
  2. // SE/schema/p5/types.xsd
  3. class SchemaHelper {
  4. /**
  5. * @param array $mysqlSchema - from infomration_schema.columns
  6. * @param required array $mysqlSchema['DATA_TYPE']
  7. * @param required array $mysqlSchema['NUMERIC_PRECISION']
  8. * @param required array $mysqlSchema['NUMERIC_SCALE']
  9. * @param required array $mysqlSchema['COLUMN_TYPE']
  10. * @param required array $mysqlSchema['IS_NULLABLE']
  11. */
  12. public static function convertMysqlTypeToSchemaXsd($mysqlSchema, $fieldName = '') {
  13. $restrictions = [];
  14. switch ($mysqlSchema['DATA_TYPE']) {
  15. case 'char':
  16. case 'varchar': {
  17. if (!empty($mysqlSchema['CHARACTER_MAXIMUM_LENGTH'])) $restrictions['maxLength'] = $mysqlSchema['CHARACTER_MAXIMUM_LENGTH'];
  18. $xsdType = 'xsd:string';
  19. } break;
  20. case 'tinyint':
  21. case 'smallint':
  22. case 'mediumint':
  23. case 'bigint':
  24. case 'int': {
  25. if (!empty($mysqlSchema['NUMERIC_PRECISION'])) $restrictions['totalDigits'] = $mysqlSchema['NUMERIC_PRECISION'];
  26. $xsdType = 'xsd:integer';
  27. } break;
  28. case 'numeric':
  29. case 'double':
  30. case 'float':
  31. case 'real':
  32. case 'decimal': {
  33. if (!empty($mysqlSchema['NUMERIC_PRECISION'])) $restrictions['totalDigits'] = $mysqlSchema['NUMERIC_PRECISION'];
  34. if (!empty($mysqlSchema['NUMERIC_SCALE'])) $restrictions['fractionDigits'] = $mysqlSchema['NUMERIC_SCALE'];
  35. $xsdType = 'xsd:decimal';
  36. } break;
  37. case 'datetime': $xsdType = 'xsd:dateTime'; break;
  38. case 'year': $xsdType = 'xsd:gYear'; break;
  39. case 'todo__year_month': $xsdType = 'xsd:gYearMonth'; break;
  40. case 'time': $xsdType = 'xsd:time'; break;
  41. case 'date': $xsdType = 'xsd:date'; break;
  42. case 'polygon': $xsdType = 'gml:PolygonPropertyType'; break;
  43. case 'linestring': $xsdType = 'gml:LineStringPropertyType'; break;
  44. case 'point': $xsdType = 'gml:PointPropertyType'; break;
  45. case 'geometry': $xsdType = 'gml:GeometryPropertyType'; break;
  46. case 'enum': {
  47. $xsdType = 'p5:enum';
  48. $restrictions['enumeration'] = [];
  49. $values = explode(',', str_replace(["'",'"'], '', substr($mysqlSchema['COLUMN_TYPE'], 5, -1)));
  50. foreach ($values as $val) {
  51. $restrictions['enumeration'][$val] = $val;
  52. }
  53. } break;
  54. case 'tinyblob': $xsdType = 'xsd:base64Binary'; break;
  55. case 'mediumblob': $xsdType = 'xsd:base64Binary'; break;
  56. case 'longblob': $xsdType = 'xsd:base64Binary'; break;
  57. case 'blob': $xsdType = 'xsd:base64Binary'; break;
  58. default: throw new Exception("Not implemented mysql schema '" . json_encode($mysqlSchema) . "'");
  59. }
  60. if ('YES' === $mysqlSchema['IS_NULLABLE']) $restrictions['nillable'] = true;
  61. // TODO: convert to p5/types.xsd
  62. switch ($xsdType) {
  63. case 'xsd:decimal': {
  64. if (12 == $restrictions['totalDigits'] && 2 == $restrictions['fractionDigits']) {
  65. // <xsd:simpleType name="price">
  66. // <xsd:restriction base="xsd:decimal">
  67. // <xsd:totalDigits value="12"/>
  68. // <xsd:fractionDigits value="2"/>
  69. unset($restrictions['totalDigits']);
  70. unset($restrictions['fractionDigits']);
  71. $xsdType = 'p5:price';
  72. }
  73. } break;
  74. case 'xsd:string': {
  75. if (255 == $restrictions['maxLength']) {
  76. unset($restrictions['maxLength']);
  77. $xsdType = 'p5:string';
  78. } else if (1000 == $restrictions['maxLength']) {
  79. unset($restrictions['maxLength']);
  80. $xsdType = 'p5:longString';
  81. }
  82. } break;
  83. }
  84. return [
  85. 'type' => $xsdType,
  86. 'restrictions' => $restrictions,
  87. '__DBG__' => [ 'COLUMN_TYPE' => $mysqlSchema['COLUMN_TYPE'] ],
  88. ];
  89. }
  90. public static function convertMysqlSchemaToXsdRestrictions($mysqlType, $fieldName = '') {
  91. $restrictions = [];
  92. // enumeration Defines a list of acceptable values
  93. // fractionDigits Specifies the maximum number of decimal places allowed. Must be equal to or greater than zero
  94. // length Specifies the exact number of characters or list items allowed. Must be equal to or greater than zero
  95. // maxExclusive Specifies the upper bounds for numeric values (the value must be less than this value)
  96. // maxInclusive Specifies the upper bounds for numeric values (the value must be less than or equal to this value)
  97. // maxLength Specifies the maximum number of characters or list items allowed. Must be equal to or greater than zero
  98. // minExclusive Specifies the lower bounds for numeric values (the value must be greater than this value)
  99. // minInclusive Specifies the lower bounds for numeric values (the value must be greater than or equal to this value)
  100. // minLength Specifies the minimum number of characters or list items allowed. Must be equal to or greater than zero
  101. // pattern Defines the exact sequence of characters that are acceptable
  102. // totalDigits Specifies the exact number of digits allowed. Must be greater than zero
  103. // whiteSpace Specifies how white space (line feeds, tabs, spaces, and carriage returns) is handled
  104. if (!empty($mysqlType['CHARACTER_MAXIMUM_LENGTH'])) $restrictions['maxLength'] = $mysqlType['CHARACTER_MAXIMUM_LENGTH'];
  105. if (!empty($mysqlType['NUMERIC_PRECISION'])) $restrictions['totalDigits'] = $mysqlType['NUMERIC_PRECISION'];
  106. if (!empty($mysqlType['NUMERIC_SCALE'])) $restrictions['fractionDigits'] = $mysqlType['NUMERIC_SCALE'];
  107. // date Defines a date value
  108. // dateTime Defines a date and time value
  109. // duration Defines a time interval
  110. // gDay Defines a part of a date - the day (DD)
  111. // gMonth Defines a part of a date - the month (MM)
  112. // gMonthDay Defines a part of a date - the month and day (MM-DD)
  113. // gYear Defines a part of a date - the year (YYYY)
  114. // gYearMonth Defines a part of a date - the year and month (YYYY-MM)
  115. // time Defines a time value
  116. if ('YES' === $mysqlType['IS_NULLABLE']) $restrictions['nillable'] = true;
  117. if (self::mysqlTypeIsEnum($mysqlType) && !empty($mysqlType['COLUMN_TYPE'])) {
  118. $restrictions['enumeration'] = [];
  119. $values = explode(',', str_replace(["'",'"'], '', substr($mysqlType['COLUMN_TYPE'], 5, -1)));
  120. foreach ($values as $val) {
  121. $restrictions['enumeration'][$val] = $val;
  122. }
  123. }
  124. $restrictions['__DBG__']['COLUMN_TYPE'] = $mysqlType['COLUMN_TYPE'];
  125. return $restrictions;
  126. }
  127. /**
  128. * @param mixed $mysqlType - string or array from INFORMATION_SCHEMA.COLUMNS
  129. */
  130. public static function convertMysqlTypeToXsd($mysqlType, $fieldName = '') {
  131. // TODO: check schemaClass
  132. // Lib::loadClass('Schema_TableFactory')
  133. // $srvName = $_SERVER['SERVER_NAME'];
  134. // $this->_schemaClass = Schema_TableFactory::build($this->_name, $this->_db, $srvName);
  135. // if ($this->_schemaClass) {
  136. // $schemaType = $this->_schemaClass->getType($fieldName);
  137. // if ($schemaType) return $schemaType;
  138. // }
  139. $fldType = 'xsd:string';
  140. if ('A_RECORD_UPDATE_DATE' == $fieldName) $fldType = 'xsd:string';// TODO: fix date format
  141. if ('A_RECORD_CREATE_DATE' == $fieldName) $fldType = 'xsd:string';// TODO: fix date format
  142. if (self::mysqlTypeIsInteger($mysqlType)) $fldType = 'xsd:integer';
  143. else if (self::mysqlTypeIsDecimal($mysqlType)) $fldType = 'xsd:decimal';
  144. else if (self::mysqlTypeIsDateTime($mysqlType)) $fldType = 'xsd:dateTime';
  145. else if (self::mysqlTypeIsDateYear($mysqlType)) $fldType = 'xsd:gYear';
  146. else if (self::mysqlTypeIsDateYearMonth($mysqlType)) $fldType = 'xsd:gYearMonth';
  147. else if (self::mysqlTypeIsTime($mysqlType)) $fldType = 'xsd:time';
  148. else if (self::mysqlTypeIsDate($mysqlType)) $fldType = 'xsd:date';
  149. else if (self::mysqlTypeIsGeometryPolygon($mysqlType)) $fldType = 'gml:PolygonPropertyType';
  150. else if (self::mysqlTypeIsGeometryLine($mysqlType)) $fldType = 'gml:LineStringPropertyType';
  151. else if (self::mysqlTypeIsGeometryPoint($mysqlType)) $fldType = 'gml:PointPropertyType';
  152. else if (self::mysqlTypeIsGeometry($mysqlType)) $fldType = 'xsd:GeometryPropertyType';
  153. else if (self::mysqlTypeIsEnum($mysqlType)) $fldType = 'p5:enum';
  154. else if (self::mysqlTypeIsBinary($mysqlType)) $fldType = 'xsd:base64Binary';
  155. DBG::log(['convertMysqlTypeToXsd', '$mysqlType' => $mysqlType, 'getMysqlType' => self::getMysqlType($mysqlType), 'return' => $fldType]);
  156. return $fldType;
  157. }
  158. /**
  159. * @param mixed $mysqlType - string or array from INFORMATION_SCHEMA.COLUMNS
  160. */
  161. public static function getMysqlType($mysqlType) {
  162. if (is_array($mysqlType)) {
  163. return $mysqlType['DATA_TYPE'];
  164. }
  165. if (false !== ($pos = strpos($mysqlType, '('))) return substr($mysqlType, 0, $pos);
  166. return $mysqlType;
  167. }
  168. public static function mysqlTypeIsInteger($mysqlType) {
  169. return (in_array(self::getMysqlType($mysqlType), ['int', 'tinyint', 'smallint', 'mediumint', 'bigint']));
  170. }
  171. public static function mysqlTypeIsDecimal($mysqlType) {
  172. return (in_array(self::getMysqlType($mysqlType), ['decimal', 'numeric', 'double', 'float', 'real']));
  173. }
  174. public static function mysqlTypeIsDateTime($mysqlType) {
  175. return (in_array(self::getMysqlType($mysqlType), ['datetime']));
  176. }
  177. public static function mysqlTypeIsDateYear($mysqlType) {
  178. return (in_array(self::getMysqlType($mysqlType), ['year']));
  179. }
  180. public static function mysqlTypeIsDateYearMonth($mysqlType) {
  181. return (in_array(self::getMysqlType($mysqlType), ['todo__year_month']));
  182. }
  183. public static function mysqlTypeIsTime($mysqlType) {
  184. return (in_array(self::getMysqlType($mysqlType), ['time']));
  185. }
  186. public static function mysqlTypeIsDate($mysqlType) {
  187. return (in_array(self::getMysqlType($mysqlType), ['date', 'datetime']));
  188. }
  189. public static function mysqlTypeIsGeometryLine($mysqlType) {
  190. return (in_array(self::getMysqlType($mysqlType), ['linestring']));
  191. }
  192. public static function mysqlTypeIsGeometryPolygon($mysqlType) {
  193. return (in_array(self::getMysqlType($mysqlType), ['polygon']));
  194. }
  195. public static function mysqlTypeIsGeometryPoint($mysqlType) {
  196. return (in_array(self::getMysqlType($mysqlType), ['point']));
  197. }
  198. public static function mysqlTypeIsGeometry($mysqlType) {
  199. return (in_array(self::getMysqlType($mysqlType), ['geometry', 'polygon', 'linestring', 'point']));
  200. }
  201. public static function mysqlTypeIsEnum($mysqlType) {
  202. return (in_array(self::getMysqlType($mysqlType), ['enum']));
  203. }
  204. public static function mysqlTypeIsBinary($mysqlType) {
  205. return (in_array(self::getMysqlType($mysqlType), ['blob', 'tinyblob', 'mediumblob', 'longblob']));
  206. }
  207. }