Region.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. declare (strict_types=1);
  3. namespace library\utils;
  4. use think\facade\Config;
  5. use think\facade\Db;
  6. use think\facade\Lang;
  7. use think\Response;
  8. class Region
  9. {
  10. public $data = [];
  11. public function __construct()
  12. {
  13. $this->data = $this->getData();
  14. }
  15. /**
  16. * 通过子集获取,全部父级
  17. * @param int $id
  18. * @param string $file 全部父级字段
  19. * @param string $Division 分割线
  20. */
  21. public function getParentS($id = 0, $file = '*', $Division = '')
  22. {
  23. $tAr = [];
  24. $rAr = [];
  25. while (true) {
  26. $data = $this->getParent($id);
  27. if (empty($data)) {
  28. break;
  29. }
  30. if (!empty($data)) {
  31. $tAr[] = $data;
  32. $id = $data['ParentId'];
  33. }
  34. }
  35. $tAr = array_reverse($tAr);
  36. foreach ($tAr as $v) {
  37. $rAr[] = ($file == '*' ? $v : $v[$file]);
  38. }
  39. if ($file != '*' && $Division != '')
  40. return join($Division, $rAr);
  41. else
  42. return $rAr;
  43. }
  44. /**
  45. * 获取子集所以Id
  46. * @param $id
  47. */
  48. public function getChildIds($id)
  49. {
  50. $rAr = $this->getChilds($id);
  51. return array_column($rAr, 'ID');
  52. }
  53. /**
  54. * 获取子集数据
  55. * @param int $id
  56. */
  57. public function getChild($id = 0)
  58. {
  59. $rAr = [];
  60. foreach ($this->data as $v) {
  61. if ($v['ParentId'] == $id) $rAr[] = $v;
  62. }
  63. return $rAr;
  64. }
  65. /**
  66. * 数据
  67. * @param int $id
  68. * @return array
  69. */
  70. public function getChilds($id = 0)
  71. {
  72. $data = $this->getChild($id);
  73. foreach ($data as $v) {
  74. $d = $this->getChilds($v['ID']);
  75. $data = array_merge($data, $d);
  76. }
  77. return $data;
  78. }
  79. /**
  80. * 上一层数
  81. * @param int $parentId
  82. * @param string $file 字段
  83. */
  84. public function getParent($parentId = 0, $file = '*')
  85. {
  86. foreach ($this->data as $v) {
  87. if ($v['ID'] == $parentId) return ($file == '*' ? $v : $v[$file]);
  88. }
  89. return null;
  90. }
  91. /**
  92. * 获取层级数据
  93. * @param int $lIndex
  94. */
  95. public function getLevel($lIndex = 0)
  96. {
  97. $rAr = [];
  98. foreach ($this->data as $v) {
  99. if ($v['LevelType'] == $lIndex) $rAr[] = $v;
  100. }
  101. return $rAr;
  102. }
  103. /**
  104. * 模糊搜索ID
  105. * @param $name
  106. * @param string $file
  107. * @param int $parentId 上一层ID
  108. * @return mixed|null
  109. */
  110. public function getLike($name, $file = '*', $parentId = -1)
  111. {
  112. if (empty($name)) return null;
  113. if ($parentId == -1)
  114. $data = $this->data;
  115. else
  116. $data = $this->getChilds($parentId);
  117. foreach ($data as $v) {
  118. if (strpos($v['Name'], $name) !== false) {
  119. return ($file == '*' ? $v : $v[$file]);
  120. }
  121. }
  122. return null;
  123. }
  124. /**
  125. * 获取地址到ID
  126. * @param $region
  127. */
  128. public function getLikeS($name)
  129. {
  130. if (empty($name)) return 0;
  131. $nameAr = explode('-', $name);
  132. $province = 0;
  133. $city = 0;
  134. $area = 0;
  135. if (!empty($nameAr)) {
  136. $province = $this->getLike($nameAr[0], 'ID');
  137. }
  138. if (count($nameAr) > 1) {
  139. $city = $this->getLike($nameAr[1], 'ID', $province);
  140. }
  141. if (count($nameAr) > 2) {
  142. $area = $this->getLike($nameAr[1], 'ID', $province);
  143. }
  144. if (!empty($area)) return $area;
  145. if (!empty($city)) return $city;
  146. if (!empty($province)) return $province;
  147. return 0;
  148. }
  149. /**
  150. * 查询地址信息
  151. * @param type $id
  152. * @param type $file
  153. * @return type
  154. */
  155. public function getField($id, $file = '*')
  156. {
  157. foreach ($this->data as $v) {
  158. if ($v['ID'] == $id) {
  159. return ($file == '*' ? $v : $v[$file]);
  160. }
  161. }
  162. return null;
  163. }
  164. public function getRegion($str)
  165. {
  166. $province = [];
  167. $city = [];
  168. $area = [];
  169. //省份获取
  170. foreach ($this->data as $v) {
  171. $item = $v;
  172. $strLen = strpos($str, $item['ProvinceShortName']);
  173. if ($item['LevelType'] == 1 && $strLen !== false && (empty($province) || $province['len'] > $strLen)
  174. ) {
  175. $v['len'] = $strLen;
  176. $v['len2'] = strlen($item['ProvinceShortName']);
  177. $province = $v;
  178. }
  179. }
  180. //城市列表
  181. if (!empty($province)) {
  182. $data = $this->getChild($province['ID']);
  183. if (count($data) == 1) {
  184. $city = $data[0];
  185. $city['len'] = 0;
  186. } else {
  187. //匹配城市 | 地址前面优先匹配
  188. $pLen = -1;
  189. foreach ($data as $v) {
  190. $str2 = substr($str . '-', $province['len'] + $province['len2'], -1);
  191. $strLen = strpos($str2, empty($v['CityShortName']) ? '' : $v['CityShortName']);
  192. if ($strLen !== false && $pLen == -1) {
  193. $pLen = $strLen;
  194. }
  195. if ($strLen !== false && $strLen <= $pLen && $v['LevelType'] == 2) {
  196. $v['len'] = $strLen + $province['len'];
  197. $city = $v;
  198. $pLen = $strLen;
  199. }
  200. }
  201. //可能城市和省会一样检测
  202. if (empty($city)) {
  203. foreach ($data as $v) {
  204. $strLen = strpos($str, empty($v['CityShortName']) ? '' : $v['CityShortName']);
  205. if ($strLen !== false && $v['LevelType'] == 2) {
  206. $v['len'] = $strLen;
  207. $city = $v;
  208. break;
  209. }
  210. }
  211. }
  212. }
  213. }
  214. //地区数据
  215. if (!empty($city)) {
  216. $data = $this->getChild($city['ID']);
  217. foreach ($data as $v) {
  218. $item = $v;
  219. $strLen = strpos($str, empty($item['DistrictShortName']) ? '' : $item['DistrictShortName']);
  220. if ($strLen !== false) {
  221. $v['len'] = $strLen;
  222. $area = $v;
  223. }
  224. }
  225. }
  226. //地区
  227. foreach ($this->data as $v) {
  228. $item = $v;
  229. $strLen = strpos($str, $item['ProvinceShortName']);
  230. if ($item['LevelType'] == 3 && $strLen !== false && empty($city) &&
  231. (empty($area) || $area['len'] < $strLen)
  232. ) {
  233. $v['len'] = $strLen;
  234. $area = $v;
  235. }
  236. }
  237. //////////// 详情地址 ////////////
  238. //省份
  239. if (!empty($province)) {
  240. $len = strpos($str, $province['Name']);
  241. $name = $province['ProvinceShortName'];
  242. if ($len !== false && $len == $province['len']) {
  243. $name = $province['Name'];
  244. }
  245. $str = $this->strReplaceLimit($name, '', $str, 1);
  246. }
  247. //城市列表
  248. if (!empty($city)) {
  249. $len = strpos($str, $city['Name']);
  250. $name = $city['CityShortName'];
  251. if ($len !== false) {
  252. $name = $city['Name'];
  253. }
  254. $str = $this->strReplaceLimit($name, '', $str, 1);
  255. }
  256. //城市列表
  257. if (!empty($area)) {
  258. $len = strpos($str, $area['Name']);
  259. $name = $area['DistrictShortName'];
  260. if ($len !== false) {
  261. $name = $area['Name'];
  262. }
  263. $str = $this->strReplaceLimit($name, '', $str, 1);
  264. }
  265. //var_dump(['address'=>trim($str),'province'=> empty($province) ? '' : $province['Name'],'city'=> empty($city) ? '' : $city['Name'],'area'=>empty($area) ? '' : $area['Name']]);
  266. return ['address' => trim($str), 'province' => empty($province) ? '' : $province['Name'], 'city' => empty($city) ? '' : $city['Name'], 'area' => empty($area) ? '' : $area['Name']];
  267. }
  268. /**
  269. * 获取基础数据【缓存数据】
  270. */
  271. private function getData()
  272. {
  273. $data = cache('region');
  274. if (empty($data)) {
  275. $data = Db::name("region")->field("ID,ParentId,LevelType,Name,Pinyin,ProvinceShortName,DistrictShortName,CityShortName")->select()->toArray();
  276. cache('region', $data);
  277. }
  278. return $data;
  279. }
  280. /**
  281. * @param $method
  282. * @param $args
  283. * @return mixed
  284. */
  285. public static function __callStatic($method, $args)
  286. {
  287. $model = new static();
  288. return call_user_func_array([$model, $method], $args);
  289. }
  290. /**
  291. * $search:要替换的字符串或者数组
  292. * $replace:要替换的值
  293. * $subject:要替换的文本
  294. * $limit:替换的此数字
  295. * @return string|string[]|null
  296. */
  297. function strReplaceLimit($search, $replace, $subject, $limit = -1)
  298. {
  299. if (is_array($search)) {
  300. foreach ($search as $k => $v) {
  301. $search[$k] = '`' . preg_quote($search[$k], '`') . '`';
  302. }
  303. } else {
  304. $search = '`' . preg_quote($search, '`') . '`';
  305. }
  306. return preg_replace($search, $replace, $subject, $limit);
  307. }
  308. }