dump.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <?php
  2. include "vendor/autoload.php";
  3. // 调试输出
  4. function vd($msg)
  5. {
  6. print_r($msg);
  7. echo PHP_EOL;
  8. }
  9. function vde($msg)
  10. {
  11. vd($msg);
  12. exit;
  13. }
  14. // 解析参数
  15. function explainArgv($argv)
  16. {
  17. $args = [];
  18. foreach ($argv as $value) {
  19. list($k, $v) = explode('=', $value);
  20. $k = ltrim(ltrim(trim($k), '--'), '-');
  21. $v = trim($v);
  22. $args[$k] = $v;
  23. }
  24. return $args;
  25. }
  26. function usage()
  27. {
  28. echo '使用示例:' . PHP_EOL;
  29. echo 'php ./dump.php -app=shot -split=false' . PHP_EOL;
  30. }
  31. class Dump
  32. {
  33. // 文件夹路径符
  34. private static $DS = '/';
  35. /**
  36. * @var string
  37. */
  38. private $appName;
  39. /**
  40. * 是否需要分子目录
  41. *
  42. * @var boolean
  43. */
  44. private $split = false;
  45. /**
  46. * 源文件目录
  47. */
  48. private $sourceDir;
  49. /**
  50. * 脚本目录
  51. */
  52. private $scriptDir;
  53. /**
  54. * 导出文件目录
  55. */
  56. private $outputDir;
  57. /**
  58. * Dump constructor.
  59. *
  60. * @param array $args
  61. */
  62. public function __construct($args)
  63. {
  64. // vd(sprintf("$args: %s", var_export($args, true)));
  65. if (!isset($args['app'])) {
  66. vd('参数错误');
  67. usage();
  68. exit;
  69. }
  70. // 初始化导出参数
  71. $this->appName = $args['app'];
  72. if (isset($args['split'])) {
  73. $this->split = $args['split'];
  74. }
  75. $this->sourceDir = __DIR__ . self::$DS . 'projects' . self::$DS . $this->appName . self::$DS . 'source';
  76. $this->scriptDir = __DIR__ . self::$DS . 'projects' . self::$DS . $this->appName . self::$DS . 'script';
  77. $this->outputDir = __DIR__ . self::$DS . 'projects' . self::$DS . $this->appName . self::$DS . 'output';
  78. // 检查目录文件是否缺失
  79. if (!is_dir($this->sourceDir)) {
  80. vde('源文件目录缺失:' . $this->sourceDir);
  81. }
  82. if (!is_dir($this->scriptDir)) {
  83. vde('脚本目录缺失:' . $this->scriptDir);
  84. }
  85. if (!is_dir($this->outputDir)) {
  86. vde('输出目录缺失:' . $this->outputDir);
  87. }
  88. }
  89. /**
  90. * 执行主函数
  91. */
  92. public function run()
  93. {
  94. // 遍历源目录, 找出所有可执行的文件
  95. $files = [];
  96. $sourceDir = dir($this->sourceDir);
  97. while ($file = $sourceDir->read()) {
  98. if ($file == '.' || $file == '..') {
  99. continue;
  100. }
  101. $pathInfo = pathinfo($file);
  102. // 现在仅支持xlsx文件
  103. if ($pathInfo['extension'] != 'xlsx') {
  104. continue;
  105. }
  106. $files[] = $pathInfo;
  107. }
  108. $sourceDir->close();
  109. if (empty($files)) {
  110. vde('源目录为空, 未找到.xlsx文件, 源目录:' . $this->sourceDir);
  111. }
  112. // 执行导出
  113. $success = 0;
  114. foreach ($files as $fileInfo) {
  115. if ($this->dump($fileInfo)) {
  116. ++$success;
  117. }
  118. }
  119. vd(sprintf("导出完成,共[%d]个文件, 成功[%d]个文件.", count($files), $success));
  120. /*
  121. // 组装导出目录
  122. $dumpBase = '..' . self::$DS . '..' . self::$DS . 'output' . self::$DS . $this->appName;
  123. self::vd($dumpBase);
  124. // 找到最后一次导出目录
  125. $lastDumpDir = $this->getLastDumpDir($dumpBase);
  126. self::vd("Last Dump Dir: " . $lastDumpDir);
  127. // 获取json文件路径
  128. $jsonPath = $lastDumpDir . self::$DS . 'PHP' . self::$DS . $this->dumpName . '.json';
  129. // 读取json文件,并解析成数组
  130. $json = $this->getJsonData($jsonPath);
  131. // 写配置文件
  132. $this->writeData($json, $lastDumpDir, $this->dumpName);
  133. // 判断此配置文件是否有特殊逻辑
  134. $methodName = $this->dumpName . '_handler';
  135. if (method_exists($this, $methodName)) {
  136. $this->$methodName($json, $lastDumpDir, $this->dumpName);
  137. self::vd("{$methodName} Done...");
  138. }
  139. // 删除json文件
  140. unlink($jsonPath);
  141. // 退出
  142. self::vd("Dump Done ...", true);
  143. */
  144. }
  145. /**
  146. * 导出表
  147. *
  148. * @param array $fileInfo
  149. * @return bool
  150. */
  151. private function dump($fileInfo)
  152. {
  153. // 找到文件对应的执行脚本
  154. $script = $this->scriptDir . self::$DS . $fileInfo['filename'] . '.php';
  155. if (!file_exists($script)) {
  156. vd(sprintf('[%s]对应的脚本文件不存在, 脚本文件:%s', $fileInfo['basename'], $script));
  157. return false;
  158. }
  159. // 引入脚本
  160. include $script;
  161. // 读取excel文件内容
  162. $sourceData = $this->getDataFromSource($this->sourceDir . self::$DS . $fileInfo['basename']);
  163. // vde($sourceData);
  164. if (count($sourceData) < $dataLine) {
  165. vd(sprintf('[%s]文件没有数据', $fileInfo['basename']));
  166. return false;
  167. }
  168. // 处理导出列对应的索引
  169. $indexes = [];
  170. // vd($sourceData[$columnLine - 1]);
  171. foreach ($sourceData[$columnLine - 1] as $index => $column) {
  172. if (isset($columns[$column])) {
  173. $indexes[$column] = $index;
  174. }
  175. }
  176. // vd($indexes);
  177. // 普通处理逻辑
  178. $data = [];
  179. foreach ($sourceData as $k => $v) {
  180. // 非数据列不处理
  181. if ($k < $dataLine - 1) {
  182. continue;
  183. }
  184. $row = [];
  185. foreach ($columns as $column => $columnType) {
  186. $columnValue = trim($v[$indexes[$column]]);
  187. switch ($columnType) {
  188. case 'float':
  189. $columnValue = floatval($columnValue);
  190. break;
  191. case 'number':
  192. $columnValue = intval($columnValue);
  193. break;
  194. case 'json':
  195. $columnValue = json_decode($columnValue, true);
  196. break;
  197. default:
  198. $columnValue = strval($columnValue);
  199. break;
  200. }
  201. $row[$column] = $columnValue;
  202. }
  203. // 跳过空行
  204. if (!$row[$keyColumn]) {
  205. continue;
  206. }
  207. $data[$row[$keyColumn]] = $row;
  208. }
  209. // 额外处理逻辑
  210. $handle = $fileInfo['filename'] . '_handle';
  211. if (function_exists($handle)) {
  212. $data = $handle($data);
  213. }
  214. // 写入文件
  215. $outputFile = $this->outputDir . self::$DS . $fileInfo['filename'] . '.config.php';
  216. $this->writeFile($outputFile, $data);
  217. return true;
  218. }
  219. /**
  220. * @param string $file 源文件地址
  221. * @return array
  222. */
  223. private function getDataFromSource($file)
  224. {
  225. $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
  226. $reader->setReadDataOnly(['Sheet 1']);
  227. $spreadsheet = $reader->load($file);
  228. $data = $spreadsheet->getActiveSheet()->toArray();
  229. return $data;
  230. }
  231. /**
  232. * 写入php文件
  233. *
  234. * @param string $file 写入文件路径
  235. * @param string $data 写入文件内容
  236. * @return void
  237. */
  238. private function writeFile($file, $data)
  239. {
  240. // 写入配置文件
  241. $configs = var_export($data, true);
  242. // 整理输出格式
  243. $config = <<<TXT
  244. <?php
  245. return {$configs};
  246. TXT;
  247. // 写入导出文件
  248. file_put_contents($file, $config);
  249. }
  250. }
  251. /*
  252. * 使用说明
  253. * php ./dump.php -app=shot -split=false
  254. */
  255. // 读取 & 解析命令行参数
  256. array_shift($argv);
  257. $args = explainArgv($argv);
  258. // 执行导出
  259. $dump = new Dump($args);
  260. $dump->run();