PageRenderTime 38ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/backend/models/ExportModel.php

https://gitlab.com/gideonmarked/atls-express
PHP | 206 lines | 106 code | 30 blank | 70 comment | 9 complexity | 2955e1ae8405b8bf630222798c91fbf4 MD5 | raw file
  1. <?php namespace Backend\Models;
  2. use File;
  3. use Lang;
  4. use Model;
  5. use Response;
  6. use League\Csv\Writer as CsvWriter;
  7. use ApplicationException;
  8. use SplTempFileObject;
  9. /**
  10. * Model used for exporting data
  11. *
  12. * @package october\backend
  13. * @author Alexey Bobkov, Samuel Georges
  14. */
  15. abstract class ExportModel extends Model
  16. {
  17. /**
  18. * Called when data is being exported.
  19. * The return value should be an array in the format of:
  20. *
  21. * [
  22. * 'db_name1' => 'Some attribute value',
  23. * 'db_name2' => 'Another attribute value'
  24. * ],
  25. * [...]
  26. *
  27. */
  28. abstract public function exportData($columns, $sessionKey = null);
  29. /**
  30. * Export data based on column names and labels.
  31. * The $columns array should be in the format of:
  32. *
  33. * [
  34. * 'db_name1' => 'Column label',
  35. * 'db_name2' => 'Another label',
  36. * ...
  37. * ]
  38. *
  39. */
  40. public function export($columns, $options)
  41. {
  42. $sessionKey = array_get($options, 'sessionKey');
  43. $data = $this->exportData(array_keys($columns), $sessionKey);
  44. return $this->processExportData($columns, $data, $options);
  45. }
  46. /**
  47. * Download a previously compiled export file.
  48. * @return void
  49. */
  50. public function download($name, $outputName = null)
  51. {
  52. if (!preg_match('/^oc[0-9a-z]*$/i', $name)) {
  53. throw new ApplicationException(Lang::get('backend::lang.import_export.file_not_found_error'));
  54. }
  55. $csvPath = temp_path() . '/' . $name;
  56. if (!file_exists($csvPath)) {
  57. throw new ApplicationException(Lang::get('backend::lang.import_export.file_not_found_error'));
  58. }
  59. $headers = Response::download($csvPath, $outputName)->headers->all();
  60. $result = Response::make(File::get($csvPath), 200, $headers);
  61. @unlink($csvPath);
  62. return $result;
  63. }
  64. /**
  65. * Converts a data collection to a CSV file.
  66. */
  67. protected function processExportData($columns, $results, $options)
  68. {
  69. /*
  70. * Validate
  71. */
  72. if (!$results) {
  73. throw new ApplicationException(Lang::get('backend::lang.import_export.empty_error'));
  74. }
  75. /*
  76. * Parse options
  77. */
  78. $defaultOptions = [
  79. 'useOutput' => false,
  80. 'fileName' => 'export.csv',
  81. 'delimiter' => null,
  82. 'enclosure' => null,
  83. 'escape' => null
  84. ];
  85. $options = array_merge($defaultOptions, $options);
  86. $columns = $this->exportExtendColumns($columns);
  87. /*
  88. * Prepare CSV
  89. */
  90. $csv = CsvWriter::createFromFileObject(new SplTempFileObject);
  91. $csv->setOutputBOM(CsvWriter::BOM_UTF8);
  92. if ($options['delimiter'] !== null) {
  93. $csv->setDelimiter($options['delimiter']);
  94. }
  95. if ($options['enclosure'] !== null) {
  96. $csv->setEnclosure($options['enclosure']);
  97. }
  98. if ($options['escape'] !== null) {
  99. $csv->setEscape($options['escape']);
  100. }
  101. /*
  102. * Add headers
  103. */
  104. $headers = $this->getColumnHeaders($columns);
  105. $csv->insertOne($headers);
  106. /*
  107. * Add records
  108. */
  109. foreach ($results as $result) {
  110. $data = $this->matchDataToColumns($result, $columns);
  111. $csv->insertOne($data);
  112. }
  113. /*
  114. * Output
  115. */
  116. if ($options['useOutput']) {
  117. $csv->output($options['fileName']);
  118. }
  119. /*
  120. * Save for download
  121. */
  122. $csvName = uniqid('oc');
  123. $csvPath = temp_path().'/'.$csvName;
  124. $output = $csv->__toString();
  125. File::put($csvPath, $output);
  126. return $csvName;
  127. }
  128. /**
  129. * Used to override column definitions at export time.
  130. */
  131. protected function exportExtendColumns($columns)
  132. {
  133. return $columns;
  134. }
  135. /**
  136. * Extracts the headers from the column definitions.
  137. */
  138. protected function getColumnHeaders($columns)
  139. {
  140. $headers = [];
  141. foreach ($columns as $column => $label) {
  142. $headers[] = Lang::get($label);
  143. }
  144. return $headers;
  145. }
  146. /**
  147. * Ensures the correct order of the column data.
  148. */
  149. protected function matchDataToColumns($data, $columns)
  150. {
  151. $results = [];
  152. foreach ($columns as $column => $label) {
  153. $results[] = array_get($data, $column);
  154. }
  155. return $results;
  156. }
  157. /**
  158. * Implodes a single dimension array using pipes (|)
  159. * Multi dimensional arrays are not allowed.
  160. * @return string
  161. */
  162. protected function encodeArrayValue($data, $delimeter = '|')
  163. {
  164. $newData = [];
  165. foreach ($data as $value) {
  166. if (is_array($value)) {
  167. $newData[] = 'Array';
  168. }
  169. else {
  170. $newData[] = str_replace($delimeter, '\\'.$delimeter, $value);
  171. }
  172. }
  173. return implode($delimeter, $newData);
  174. }
  175. }