SchemaHelper.php 10 KB

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