Helper.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. <?php
  2. namespace Dcat\Admin\Support;
  3. use Dcat\Admin\Grid;
  4. use Illuminate\Contracts\Support\Arrayable;
  5. use Illuminate\Contracts\Support\Htmlable;
  6. use Illuminate\Contracts\Support\Jsonable;
  7. use Illuminate\Contracts\Support\Renderable;
  8. use Illuminate\Http\Request;
  9. use Illuminate\Support\Arr;
  10. use Illuminate\Support\Facades\Artisan;
  11. use Illuminate\Support\Facades\File;
  12. use Illuminate\Support\Str;
  13. class Helper
  14. {
  15. /**
  16. * @var array
  17. */
  18. public static $fileTypes = [
  19. 'image' => 'png|jpg|jpeg|tmp|gif',
  20. 'word' => 'doc|docx',
  21. 'excel' => 'xls|xlsx|csv',
  22. 'powerpoint' => 'ppt|pptx',
  23. 'pdf' => 'pdf',
  24. 'code' => 'php|js|java|python|ruby|go|c|cpp|sql|m|h|json|html|aspx',
  25. 'archive' => 'zip|tar\.gz|rar|rpm',
  26. 'txt' => 'txt|pac|log|md',
  27. 'audio' => 'mp3|wav|flac|3pg|aa|aac|ape|au|m4a|mpc|ogg',
  28. 'video' => 'mkv|rmvb|flv|mp4|avi|wmv|rm|asf|mpeg',
  29. ];
  30. /**
  31. * 更新扩展配置.
  32. *
  33. * @param array $config
  34. *
  35. * @return bool
  36. */
  37. public static function updateExtensionConfig(array $config)
  38. {
  39. $files = app('files');
  40. $result = (bool) $files->put(config_path('admin-extensions.php'), self::exportArrayPhp($config));
  41. if ($result && is_file(base_path('bootstrap/cache/config.php'))) {
  42. Artisan::call('config:cache');
  43. }
  44. config(['admin-extensions' => $config]);
  45. return $result;
  46. }
  47. /**
  48. * 把给定的值转化为数组.
  49. *
  50. * @param $value
  51. * @param bool $filter
  52. *
  53. * @return array
  54. */
  55. public static function array($value, bool $filter = true): array
  56. {
  57. if (! $value) {
  58. return [];
  59. }
  60. if ($value instanceof \Closure) {
  61. $value = $value();
  62. }
  63. if (is_array($value)) {
  64. } elseif ($value instanceof Jsonable) {
  65. $value = json_decode($value->toJson(), true);
  66. } elseif ($value instanceof Arrayable) {
  67. $value = $value->toArray();
  68. } elseif (is_string($value)) {
  69. $array = null;
  70. try {
  71. $array = json_decode($value, true);
  72. } catch (\Throwable $e) {
  73. }
  74. $value = is_array($array) ? $array : explode(',', $value);
  75. } else {
  76. $value = (array) $value;
  77. }
  78. return $filter ? array_filter($value, function ($v) {
  79. return $v !== '' && $v !== null;
  80. }) : $value;
  81. }
  82. /**
  83. * 把给定的值转化为字符串.
  84. *
  85. * @param string|Grid|\Closure|Renderable|Htmlable $value
  86. * @param array $params
  87. * @param object $newThis
  88. *
  89. * @return string
  90. */
  91. public static function render($value, $params = [], $newThis = null): string
  92. {
  93. if (is_string($value)) {
  94. return $value;
  95. }
  96. if ($value instanceof Grid) {
  97. return (string) $value->render();
  98. }
  99. if ($value instanceof \Closure) {
  100. $newThis && $value = $value->bindTo($newThis);
  101. $value = $value(...(array) $params);
  102. }
  103. if ($value instanceof Renderable) {
  104. return (string) $value->render();
  105. }
  106. if ($value instanceof Htmlable) {
  107. return (string) $value->toHtml();
  108. }
  109. return (string) $value;
  110. }
  111. /**
  112. * @param array $attributes
  113. *
  114. * @return string
  115. */
  116. public static function buildHtmlAttributes($attributes)
  117. {
  118. $html = '';
  119. foreach ((array) $attributes as $key => &$value) {
  120. if (is_array($value)) {
  121. $value = implode(' ', $value);
  122. }
  123. if (is_numeric($key)) {
  124. $key = $value;
  125. }
  126. $element = '';
  127. if ($value !== null) {
  128. $element = $key.'="'.htmlentities($value, ENT_QUOTES, 'UTF-8').'"';
  129. }
  130. $html .= $element;
  131. }
  132. return $html;
  133. }
  134. /**
  135. * @param string $url
  136. * @param array $query
  137. *
  138. * @return string
  139. */
  140. public static function urlWithQuery(?string $url, array $query = [])
  141. {
  142. if (! $url || ! $query) {
  143. return $url;
  144. }
  145. $array = explode('?', $url);
  146. $url = $array[0];
  147. parse_str($array[1] ?? '', $originalQuery);
  148. return $url.'?'.http_build_query(array_merge($originalQuery, $query));
  149. }
  150. /**
  151. * @param string $url
  152. * @param string|array|Arrayable $keys
  153. *
  154. * @return string
  155. */
  156. public static function urlWithoutQuery($url, $keys)
  157. {
  158. if (! Str::contains($url, '?') || ! $keys) {
  159. return $url;
  160. }
  161. if ($keys instanceof Arrayable) {
  162. $keys = $keys->toArray();
  163. }
  164. $keys = (array) $keys;
  165. $urlInfo = parse_url($url);
  166. parse_str($urlInfo['query'], $query);
  167. Arr::forget($query, $keys);
  168. $baseUrl = explode('?', $url)[0];
  169. return $query
  170. ? $baseUrl.'?'.http_build_query($query)
  171. : $baseUrl;
  172. }
  173. /**
  174. * @param Arrayable|array|string $keys
  175. *
  176. * @return string
  177. */
  178. public static function fullUrlWithoutQuery($keys)
  179. {
  180. return static::urlWithoutQuery(request()->fullUrl(), $keys);
  181. }
  182. /**
  183. * @param string $url
  184. * @param string|array $keys
  185. *
  186. * @return bool
  187. */
  188. public static function urlHasQuery(string $url, $keys)
  189. {
  190. $value = explode('?', $url);
  191. if (empty($value[1])) {
  192. return false;
  193. }
  194. parse_str($value[1], $query);
  195. foreach ((array) $keys as $key) {
  196. if (Arr::has($query, $key)) {
  197. return true;
  198. }
  199. }
  200. return false;
  201. }
  202. /**
  203. * 匹配请求路径.
  204. *
  205. * @example
  206. * Helper::matchRequestPath(admin_base_path('auth/user'))
  207. * Helper::matchRequestPath(admin_base_path('auth/user*'))
  208. * Helper::matchRequestPath(admin_base_path('auth/user/* /edit'))
  209. * Helper::matchRequestPath('GET,POST:auth/user')
  210. *
  211. * @param string $path
  212. * @param null|string $current
  213. *
  214. * @return bool
  215. */
  216. public static function matchRequestPath($path, ?string $current = null)
  217. {
  218. $request = request();
  219. $current = $current ?: $request->decodedPath();
  220. if (Str::contains($path, ':')) {
  221. [$methods, $path] = explode(':', $path);
  222. $methods = array_map('strtoupper', explode(',', $methods));
  223. if (! empty($methods) && ! in_array($request->method(), $methods)) {
  224. return false;
  225. }
  226. }
  227. // 判断路由名称
  228. if ($request->routeIs($path)) {
  229. return true;
  230. }
  231. if (! Str::contains($path, '*')) {
  232. return $path === $current;
  233. }
  234. $path = str_replace(['*', '/'], ['([0-9a-z-_,])*', "\/"], $path);
  235. return preg_match("/$path/i", $current);
  236. }
  237. /**
  238. * 生成层级数据.
  239. *
  240. * @param array $nodes
  241. * @param int $parentId
  242. * @param string|null $primaryKeyName
  243. * @param string|null $parentKeyName
  244. * @param string|null $childrenKeyName
  245. *
  246. * @return array
  247. */
  248. public static function buildNestedArray(
  249. $nodes = [],
  250. $parentId = 0,
  251. ?string $primaryKeyName = null,
  252. ?string $parentKeyName = null,
  253. ?string $childrenKeyName = null
  254. ) {
  255. $branch = [];
  256. $primaryKeyName = $primaryKeyName ?: 'id';
  257. $parentKeyName = $parentKeyName ?: 'parent_id';
  258. $childrenKeyName = $childrenKeyName ?: 'children';
  259. $parentId = is_numeric($parentId) ? (int) $parentId : $parentId;
  260. foreach ($nodes as $node) {
  261. $pk = Arr::get($node, $parentKeyName);
  262. $pk = is_numeric($pk) ? (int) $pk : $pk;
  263. if ($pk === $parentId) {
  264. $children = static::buildNestedArray(
  265. $nodes,
  266. Arr::get($node, $primaryKeyName),
  267. $primaryKeyName,
  268. $parentKeyName,
  269. $childrenKeyName
  270. );
  271. if ($children) {
  272. $node[$childrenKeyName] = $children;
  273. }
  274. $branch[] = $node;
  275. }
  276. }
  277. return $branch;
  278. }
  279. /**
  280. * @param string $name
  281. * @param string $symbol
  282. *
  283. * @return mixed
  284. */
  285. public static function slug(string $name, string $symbol = '-')
  286. {
  287. $text = preg_replace_callback('/([A-Z])/', function (&$text) use ($symbol) {
  288. return $symbol.strtolower($text[1]);
  289. }, $name);
  290. return str_replace('_', $symbol, ltrim($text, $symbol));
  291. }
  292. /**
  293. * @param array $array
  294. * @param int $level
  295. *
  296. * @return string
  297. */
  298. public static function exportArray(array &$array, $level = 1)
  299. {
  300. $start = '[';
  301. $end = ']';
  302. $txt = "$start\n";
  303. foreach ($array as $k => &$v) {
  304. if (is_array($v)) {
  305. $pre = is_string($k) ? "'$k' => " : "$k => ";
  306. $txt .= str_repeat(' ', $level * 4).$pre.static::exportArray($v, $level + 1).",\n";
  307. continue;
  308. }
  309. $t = $v;
  310. if ($v === true) {
  311. $t = 'true';
  312. } elseif ($v === false) {
  313. $t = 'false';
  314. } elseif ($v === null) {
  315. $t = 'null';
  316. } elseif (is_string($v)) {
  317. $v = str_replace("'", "\\'", $v);
  318. $t = "'$v'";
  319. }
  320. $pre = is_string($k) ? "'$k' => " : "$k => ";
  321. $txt .= str_repeat(' ', $level * 4)."{$pre}{$t},\n";
  322. }
  323. return $txt.str_repeat(' ', ($level - 1) * 4).$end;
  324. }
  325. /**
  326. * @param array $array
  327. *
  328. * @return string
  329. */
  330. public static function exportArrayPhp(array $array)
  331. {
  332. return "<?php \nreturn ".static::exportArray($array).";\n";
  333. }
  334. /**
  335. * 删除数组中的元素.
  336. *
  337. * @param array $array
  338. * @param mixed $value
  339. */
  340. public static function deleteByValue(&$array, $value)
  341. {
  342. $value = (array) $value;
  343. foreach ($array as $index => $item) {
  344. if (in_array($item, $value)) {
  345. unset($array[$index]);
  346. }
  347. }
  348. }
  349. /**
  350. * 颜色转亮.
  351. *
  352. * @param string $color
  353. * @param int $amt
  354. *
  355. * @return string
  356. */
  357. public static function colorLighten(string $color, int $amt)
  358. {
  359. if (! $amt) {
  360. return $color;
  361. }
  362. $hasPrefix = false;
  363. if (mb_strpos($color, '#') === 0) {
  364. $color = mb_substr($color, 1);
  365. $hasPrefix = true;
  366. }
  367. [$red, $blue, $green] = static::colorToRBG($color, $amt);
  368. return ($hasPrefix ? '#' : '').dechex($green + ($blue << 8) + ($red << 16));
  369. }
  370. /**
  371. * 颜色转暗.
  372. *
  373. * @param string $color
  374. * @param int $amt
  375. *
  376. * @return string
  377. */
  378. public static function colorDarken(string $color, int $amt)
  379. {
  380. return static::colorLighten($color, -$amt);
  381. }
  382. /**
  383. * 颜色透明度.
  384. *
  385. * @param string $color
  386. * @param float|string $alpha
  387. *
  388. * @return string
  389. */
  390. public static function colorAlpha(string $color, $alpha)
  391. {
  392. if ($alpha >= 1) {
  393. return $color;
  394. }
  395. if (mb_strpos($color, '#') === 0) {
  396. $color = mb_substr($color, 1);
  397. }
  398. [$red, $blue, $green] = static::colorToRBG($color);
  399. return "rgba($red, $blue, $green, $alpha)";
  400. }
  401. /**
  402. * @param string $color
  403. * @param int $amt
  404. *
  405. * @return array
  406. */
  407. public static function colorToRBG(string $color, int $amt = 0)
  408. {
  409. $format = function ($value) {
  410. if ($value > 255) {
  411. return 255;
  412. }
  413. if ($value < 0) {
  414. return 0;
  415. }
  416. return $value;
  417. };
  418. $num = hexdec($color);
  419. $red = $format(($num >> 16) + $amt);
  420. $blue = $format((($num >> 8) & 0x00FF) + $amt);
  421. $green = $format(($num & 0x0000FF) + $amt);
  422. return [$red, $blue, $green];
  423. }
  424. /**
  425. * 验证扩展包名称.
  426. *
  427. * @param string $name
  428. *
  429. * @return int
  430. */
  431. public static function validateExtensionName($name)
  432. {
  433. return preg_match('/^[\w\-_]+\/[\w\-_]+$/', $name);
  434. }
  435. /**
  436. * Get file icon.
  437. *
  438. * @param string $file
  439. *
  440. * @return string
  441. */
  442. public static function getFileIcon($file = '')
  443. {
  444. $extension = File::extension($file);
  445. foreach (static::$fileTypes as $type => $regex) {
  446. if (preg_match("/^($regex)$/i", $extension) !== 0) {
  447. return "fa fa-file-{$type}-o";
  448. }
  449. }
  450. return 'fa fa-file-o';
  451. }
  452. /**
  453. * 判断是否是ajax请求.
  454. *
  455. * @param Request $request
  456. *
  457. * @return bool
  458. */
  459. public static function isAjaxRequest(?Request $request = null)
  460. {
  461. /* @var Request $request */
  462. $request = $request ?: request();
  463. return $request->ajax() && ! $request->pjax();
  464. }
  465. }