AbstractExporter.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <?php
  2. namespace Dcat\Admin\Grid\Exporters;
  3. use Dcat\Admin\Grid;
  4. use Illuminate\Support\Arr;
  5. use Illuminate\Support\Collection;
  6. use Illuminate\Support\Str;
  7. /**
  8. * @method $this disableExportAll(bool $value = true)
  9. * @method $this disableExportCurrentPage(bool $value = true)
  10. * @method $this disableExportSelectedRow(bool $value = true)
  11. */
  12. abstract class AbstractExporter implements ExporterInterface
  13. {
  14. /**
  15. * @var \Dcat\Admin\Grid
  16. */
  17. protected $grid;
  18. /**
  19. * @var Grid\Exporter
  20. */
  21. protected $parent;
  22. /**
  23. * @var \Closure
  24. */
  25. protected $builder;
  26. /**
  27. * @var array
  28. */
  29. protected $titles = [];
  30. /**
  31. * @var string
  32. */
  33. protected $filename;
  34. /**
  35. * @var string
  36. */
  37. protected $scope;
  38. /**
  39. * @var string
  40. */
  41. protected $extension = 'xlsx';
  42. /**
  43. * Create a new exporter instance.
  44. *
  45. * @param array $titles
  46. */
  47. public function __construct($titles = [])
  48. {
  49. if ($titles) {
  50. $this->titles($titles);
  51. }
  52. }
  53. /**
  54. * Set the headings of excel sheet.
  55. *
  56. * @param array|false $titles
  57. * @return $this|array
  58. */
  59. public function titles($titles = null)
  60. {
  61. if ($titles === null) {
  62. return $this->titles ?: ($this->titles = $this->defaultTitles());
  63. }
  64. if (is_array($titles) || $titles === false) {
  65. $this->titles = $titles;
  66. }
  67. return $this;
  68. }
  69. /**
  70. * 读取默认标题.
  71. *
  72. * @return array
  73. */
  74. protected function defaultTitles()
  75. {
  76. return $this
  77. ->grid
  78. ->columns()
  79. ->mapWithKeys(function (Grid\Column $column, $name) {
  80. return [$name => $column->getLabel()];
  81. })
  82. ->reject(function ($v, $k) {
  83. return in_array($k, ['#', Grid\Column::ACTION_COLUMN_NAME, Grid\Column::SELECT_COLUMN_NAME]);
  84. })
  85. ->toArray();
  86. }
  87. /**
  88. * Set filename.
  89. *
  90. * @param string|\Closure $filename
  91. * @return $this
  92. */
  93. public function filename($filename)
  94. {
  95. $this->filename = value($filename);
  96. return $this;
  97. }
  98. /**
  99. * Set export data callback function.
  100. *
  101. * @param \Closure $builder
  102. * @return $this
  103. */
  104. public function rows(\Closure $builder)
  105. {
  106. $this->builder = $builder;
  107. return $this;
  108. }
  109. /**
  110. * @return $this
  111. */
  112. public function xlsx()
  113. {
  114. return $this->extension('xlsx');
  115. }
  116. /**
  117. * @return $this
  118. */
  119. public function csv()
  120. {
  121. return $this->extension('csv');
  122. }
  123. /**
  124. * @return $this
  125. */
  126. public function ods()
  127. {
  128. return $this->extension('ods');
  129. }
  130. /**
  131. * @param string $ext e.g. csv/xlsx/ods
  132. * @return $this
  133. */
  134. public function extension(string $ext)
  135. {
  136. $this->extension = $ext;
  137. return $this;
  138. }
  139. /**
  140. * Set grid for exporter.
  141. *
  142. * @param Grid $grid
  143. * @return $this
  144. */
  145. public function setGrid(Grid $grid)
  146. {
  147. $this->grid = $grid;
  148. $this->parent = $grid->exporter();
  149. return $this;
  150. }
  151. /**
  152. * @return string
  153. */
  154. public function getFilename()
  155. {
  156. return $this->filename ?: (admin_trans_label().'-'.date('Ymd-His').'-'.Str::random(6));
  157. }
  158. /**
  159. * Get data with export query.
  160. *
  161. * @param int $page
  162. * @param int $perPage
  163. * @return array|\Illuminate\Support\Collection|mixed
  164. */
  165. public function buildData(?int $page = null, ?int $perPage = null)
  166. {
  167. $model = $this->getGridModel();
  168. // current page
  169. if ($this->scope === Grid\Exporter::SCOPE_CURRENT_PAGE) {
  170. $page = $model->getCurrentPage();
  171. $perPage = $model->getPerPage();
  172. }
  173. $model->usePaginate(false);
  174. if ($page && $this->scope !== Grid\Exporter::SCOPE_SELECTED_ROWS) {
  175. $perPage = $perPage ?: $this->getChunkSize();
  176. $model->forPage($page, $perPage);
  177. }
  178. $array = $this->grid->processFilter();
  179. $model->reset();
  180. return $this->normalize($this->callBuilder($array));
  181. }
  182. /**
  183. * 格式化待导出数据.
  184. *
  185. * @param Collection $data
  186. * @return array
  187. */
  188. protected function normalize(Collection $data)
  189. {
  190. $data = $data->toArray();
  191. foreach ($data as &$row) {
  192. $row = Arr::dot($row);
  193. foreach ($row as &$v) {
  194. if (is_array($v) || is_object($v)) {
  195. $v = json_encode($v, JSON_UNESCAPED_UNICODE);
  196. }
  197. }
  198. }
  199. return $data;
  200. }
  201. /**
  202. * @return Grid\Model
  203. */
  204. protected function getGridModel()
  205. {
  206. $model = $this->grid->model();
  207. if (empty($this->modelQueries)) {
  208. $model->rejectQuery(['forPage']);
  209. $this->modelQueries = clone $model->getQueries();
  210. }
  211. $model->setQueries($this->modelQueries);
  212. return $model;
  213. }
  214. /**
  215. * @param Collection $data
  216. * @return array
  217. */
  218. protected function callBuilder(Collection &$data)
  219. {
  220. if ($data && $this->builder) {
  221. return ($this->builder)($data);
  222. }
  223. return $data;
  224. }
  225. /**
  226. * @return int
  227. */
  228. protected function getChunkSize()
  229. {
  230. return $this->parent->option('chunk_size') ?: 5000;
  231. }
  232. /**
  233. * Export data with scope.
  234. *
  235. * @param string $scope
  236. * @return $this
  237. */
  238. public function withScope($scope)
  239. {
  240. $data = explode(':', $scope);
  241. $scope = $data[0] ?? '';
  242. $args = $data[1] ?? '';
  243. $this->scope = $scope;
  244. if ($scope == Grid\Exporter::SCOPE_SELECTED_ROWS) {
  245. $selected = explode(',', $args);
  246. $this->grid->model()->whereIn($this->grid->getKeyName(), $selected);
  247. }
  248. return $this;
  249. }
  250. /**
  251. * {@inheritdoc}
  252. */
  253. abstract public function export();
  254. /**
  255. * @param $method
  256. * @param $arguments
  257. * @return mixed
  258. */
  259. public function __call($method, $arguments)
  260. {
  261. $this->parent->{$method}(...$arguments);
  262. return $this;
  263. }
  264. /**
  265. * Create a new exporter instance.
  266. *
  267. * @param \Closure|array $closure
  268. */
  269. public static function make($builder = null)
  270. {
  271. return new static($builder);
  272. }
  273. }