| 1 | <?php |
|---|
| 2 | |
|---|
| 3 | class QDataGridExporterButton extends QButton { |
|---|
| 4 | private $dtgSourceDatagrid = array(); |
|---|
| 5 | |
|---|
| 6 | const DOWNLOAD_ENTIRE_DATAGRID = 1; |
|---|
| 7 | const DOWNLOAD_CURRENT_PAGE = 2; |
|---|
| 8 | private $intDownloadMode; |
|---|
| 9 | |
|---|
| 10 | const EXPORT_AS_XLS = 1; |
|---|
| 11 | const EXPORT_AS_CSV = 2; |
|---|
| 12 | private $intExportFormat; |
|---|
| 13 | |
|---|
| 14 | public function __construct($objParentObject, QPaginatedControl $dtgobj, $strControlId = null) { |
|---|
| 15 | parent::__construct($objParentObject, $strControlId); |
|---|
| 16 | |
|---|
| 17 | $this->Text = "Download"; |
|---|
| 18 | $this->intExportFormat = self::EXPORT_AS_CSV; |
|---|
| 19 | $this->intDownloadMode = self::DOWNLOAD_ENTIRE_DATAGRID; |
|---|
| 20 | |
|---|
| 21 | $this->AddAction(new QClickEvent(), new QServerControlAction($this, 'btnExport_clicked')); |
|---|
| 22 | |
|---|
| 23 | $this->dtgSourceDatagrid = $dtgobj; |
|---|
| 24 | } |
|---|
| 25 | |
|---|
| 26 | |
|---|
| 27 | public function __set($strName,$mixValue) { |
|---|
| 28 | switch ($strName) { |
|---|
| 29 | case "DownloadFormat": |
|---|
| 30 | try { |
|---|
| 31 | $this->intExportFormat = QType::Cast($mixValue, QType::Integer); |
|---|
| 32 | break; |
|---|
| 33 | } catch (QInvalidCastException $objExc) { |
|---|
| 34 | $objExc->IncrementOffset(); |
|---|
| 35 | throw $objExc; |
|---|
| 36 | } |
|---|
| 37 | |
|---|
| 38 | case "DownloadMode": |
|---|
| 39 | try { |
|---|
| 40 | $this->intDownloadMode = QType::Cast($mixValue, QType::Integer); |
|---|
| 41 | break; |
|---|
| 42 | } catch (QInvalidCastException $objExc) { |
|---|
| 43 | $objExc->IncrementOffset(); |
|---|
| 44 | throw $objExc; |
|---|
| 45 | } |
|---|
| 46 | |
|---|
| 47 | default: |
|---|
| 48 | try { |
|---|
| 49 | parent::__set($strName, $mixValue); |
|---|
| 50 | break; |
|---|
| 51 | } catch (QCallerException $objExc) { |
|---|
| 52 | $objExc->IncrementOffset(); |
|---|
| 53 | throw $objExc; |
|---|
| 54 | } |
|---|
| 55 | } |
|---|
| 56 | } |
|---|
| 57 | |
|---|
| 58 | private function streamCSV() { |
|---|
| 59 | $data = $this->dtgSourceDatagrid->DataSource; |
|---|
| 60 | $columns = $this->dtgSourceDatagrid->GetAllColumns(); |
|---|
| 61 | |
|---|
| 62 | // Get header names |
|---|
| 63 | $header = array(); |
|---|
| 64 | foreach($columns as $column){ |
|---|
| 65 | // Get the column names but strip off any html tags in case we have got a sort ref. |
|---|
| 66 | $header[] = strip_tags($column->Name); |
|---|
| 67 | } |
|---|
| 68 | //QFirebug::log($header); |
|---|
| 69 | |
|---|
| 70 | // get the data rows |
|---|
| 71 | $rows = array(); |
|---|
| 72 | foreach($data as $item){ |
|---|
| 73 | $values = array(); |
|---|
| 74 | foreach($columns as $column){ |
|---|
| 75 | // Get the values but strip off any html tags in case we have got a button or so. |
|---|
| 76 | // $values[] = strip_tags(QDataGrid::ParseHtml($column->Html,$this->dtgSourceDatagrid,$column,$item)); |
|---|
| 77 | $tmp = strip_tags(QDataGrid::ParseHtml($column->Html,$this->dtgSourceDatagrid,$column,$item)); |
|---|
| 78 | // Excel get confused..and loose precision forcing exponential |
|---|
| 79 | // if $column content is numeric, but more than 15 character |
|---|
| 80 | $tmp = $this->excel_patch_num($tmp); |
|---|
| 81 | $values[] = $tmp; |
|---|
| 82 | } |
|---|
| 83 | $rows[] = $values; |
|---|
| 84 | } |
|---|
| 85 | //QFirebug::log($rows); |
|---|
| 86 | |
|---|
| 87 | // Change heaser info |
|---|
| 88 | session_cache_limiter('must-revalidate'); // Blaine's fix for SSL & PHP Sessions |
|---|
| 89 | header("Pragma: hack"); // IE chokes on "no cache", so set to something, anything, else. |
|---|
| 90 | $ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time()) . " GMT"; |
|---|
| 91 | header($ExpStr); |
|---|
| 92 | |
|---|
| 93 | header("Content-type: text/csv"); |
|---|
| 94 | header("Content-disposition: csv; filename=" . date("Y-m-d") ."_datagrid_export.csv"); |
|---|
| 95 | |
|---|
| 96 | // Spit out header |
|---|
| 97 | echo $this->getCsvRowFromArray($header); |
|---|
| 98 | echo "\n"; |
|---|
| 99 | // Spit out rows |
|---|
| 100 | foreach($rows as $row){ |
|---|
| 101 | echo $this->getCsvRowFromArray($row); |
|---|
| 102 | echo "\n"; |
|---|
| 103 | } |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | private function streamXLS() { |
|---|
| 107 | $data = $this->dtgSourceDatagrid->DataSource; |
|---|
| 108 | $columns = $this->dtgSourceDatagrid->GetAllColumns(); |
|---|
| 109 | |
|---|
| 110 | // Get table header names |
|---|
| 111 | $theader = array(); |
|---|
| 112 | $theader[] = "<table>"; |
|---|
| 113 | $theader[] = "<thead>"; |
|---|
| 114 | $theader[] = "<tr>"; |
|---|
| 115 | |
|---|
| 116 | foreach($columns as $column){ |
|---|
| 117 | // Get the column names but strip off any html tags in case we have got a sort ref. |
|---|
| 118 | $theader[] = sprintf("\n<td>%s</td>" ,strip_tags($column->Name)); |
|---|
| 119 | } |
|---|
| 120 | $theader[] = "\n</tr></thead>"; |
|---|
| 121 | |
|---|
| 122 | //QFirebug::log($theader); |
|---|
| 123 | |
|---|
| 124 | // get the data rows |
|---|
| 125 | $rows = array(); |
|---|
| 126 | foreach($data as $item){ |
|---|
| 127 | $values = array(); |
|---|
| 128 | foreach($columns as $column){ |
|---|
| 129 | // Get the values but strip off any html tags in case we have got a button or so. |
|---|
| 130 | $tmp = strip_tags(QDataGrid::ParseHtml($column->Html,$this->dtgSourceDatagrid,$column,$item)); |
|---|
| 131 | // Excel get confused..and loose precision forcing exponential |
|---|
| 132 | // if $column content is numeric, but more than 15 character |
|---|
| 133 | $tmp = $this->excel_patch_num($tmp); |
|---|
| 134 | $values[] = sprintf("\n<td>%s</td>", $tmp); |
|---|
| 135 | } |
|---|
| 136 | $rows[] = $values; |
|---|
| 137 | } |
|---|
| 138 | //QFirebug::log($rows); |
|---|
| 139 | |
|---|
| 140 | $Html_open='<html xmlns:o="urn:schemas-microsoft-com:office:office" |
|---|
| 141 | xmlns:x="urn:schemas-microsoft-com:office:excel" |
|---|
| 142 | xmlns="http://www.w3.org/TR/REC-html40"> |
|---|
| 143 | <head>'; |
|---|
| 144 | $Html_open = str_replace("\t","", $Html_open); |
|---|
| 145 | echo $Html_open; |
|---|
| 146 | |
|---|
| 147 | // Change header info |
|---|
| 148 | session_cache_limiter('must-revalidate'); // Blaine's fix for SSL & PHP Sessions |
|---|
| 149 | header("Pragma: hack"); // IE chokes on "no cache", so set to something, anything, else. |
|---|
| 150 | $ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time()) . " GMT"; |
|---|
| 151 | header($ExpStr); |
|---|
| 152 | |
|---|
| 153 | header("Content-type: text/xls"); |
|---|
| 154 | header("Content-disposition: xls; filename=" . date("Y-m-d") ."_datagrid_export.xls"); |
|---|
| 155 | // excel xml info ( tested with my office 2000 - to have datagrid and active cell a1) |
|---|
| 156 | |
|---|
| 157 | echo $this->format_XLS_head(); |
|---|
| 158 | // Spit out table header |
|---|
| 159 | echo $this->getRowFromArray($theader); |
|---|
| 160 | echo "\n<tbody>"; |
|---|
| 161 | // Spit out rows |
|---|
| 162 | foreach($rows as $row){ |
|---|
| 163 | echo "\n<tr>"; |
|---|
| 164 | echo $this->getRowFromArray($row); |
|---|
| 165 | echo "\n</tr>"; |
|---|
| 166 | } |
|---|
| 167 | echo "</tbody>\n</table>\n</body>\n</html>"; |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | |
|---|
| 171 | public function btnExport_clicked ($strFormId, $strControlId, $strParameter) { |
|---|
| 172 | // Data bind. What will happen if the grid has got a paginator? |
|---|
| 173 | |
|---|
| 174 | // this two lines confuse paginator an have all pages. |
|---|
| 175 | //QFirebug::log($this->intDownloadMode); |
|---|
| 176 | if($this->intDownloadMode == self::DOWNLOAD_ENTIRE_DATAGRID) { |
|---|
| 177 | $this->dtgSourceDatagrid->ItemsPerPage = 2147483647; |
|---|
| 178 | $this->dtgSourceDatagrid->PageNumber = 1; |
|---|
| 179 | } |
|---|
| 180 | $this->dtgSourceDatagrid->DataBind(); |
|---|
| 181 | |
|---|
| 182 | switch ($this->intExportFormat) { |
|---|
| 183 | case self::EXPORT_AS_CSV: |
|---|
| 184 | $this->streamCSV(); |
|---|
| 185 | break; |
|---|
| 186 | case self::EXPORT_AS_XLS: |
|---|
| 187 | $this->streamXLS(); |
|---|
| 188 | break; |
|---|
| 189 | default: |
|---|
| 190 | throw new QCallerException("Invalid export format: ") . $this->intExportFormat; |
|---|
| 191 | } |
|---|
| 192 | |
|---|
| 193 | exit(); |
|---|
| 194 | } |
|---|
| 195 | |
|---|
| 196 | private function format_XLS_head() { |
|---|
| 197 | $result = "\n"; |
|---|
| 198 | $result .= '<!--[if gte mso 9]><xml> |
|---|
| 199 | <x:ExcelWorkbook> |
|---|
| 200 | <x:ExcelWorksheets> |
|---|
| 201 | <x:ExcelWorksheet> |
|---|
| 202 | <x:Name>2010-01-16_datagrid_export</x:Name> |
|---|
| 203 | <x:WorksheetOptions> |
|---|
| 204 | <x:Selected/> |
|---|
| 205 | <x:DisplayGridlines/> |
|---|
| 206 | <x:Panes> |
|---|
| 207 | <x:Pane> |
|---|
| 208 | <x:Number>3</x:Number> |
|---|
| 209 | <x:ActiveRow>1</x:ActiveRow> |
|---|
| 210 | <x:ActiveCol>1</x:ActiveCol> |
|---|
| 211 | </x:Pane> |
|---|
| 212 | </x:Panes> |
|---|
| 213 | <x:ProtectContents>False</x:ProtectContents> |
|---|
| 214 | <x:ProtectObjects>False</x:ProtectObjects> |
|---|
| 215 | <x:ProtectScenarios>False</x:ProtectScenarios> |
|---|
| 216 | </x:WorksheetOptions> |
|---|
| 217 | </x:ExcelWorksheet> |
|---|
| 218 | </x:ExcelWorksheets> |
|---|
| 219 | <x:WindowHeight>10230</x:WindowHeight> |
|---|
| 220 | <x:WindowWidth>18075</x:WindowWidth> |
|---|
| 221 | <x:WindowTopX>360</x:WindowTopX> |
|---|
| 222 | <x:WindowTopY>60</x:WindowTopY> |
|---|
| 223 | <x:ProtectStructure>False</x:ProtectStructure> |
|---|
| 224 | <x:ProtectWindows>False</x:ProtectWindows> |
|---|
| 225 | </x:ExcelWorkbook> |
|---|
| 226 | </xml><![endif]--> |
|---|
| 227 | </head> |
|---|
| 228 | <body>'; |
|---|
| 229 | |
|---|
| 230 | // remove tabs |
|---|
| 231 | $result = str_replace("\t","",$result); |
|---|
| 232 | return $result; |
|---|
| 233 | } |
|---|
| 234 | |
|---|
| 235 | private function getCsvRowFromArray($arrRow){ |
|---|
| 236 | $result = ""; |
|---|
| 237 | if(is_array($arrRow)){ |
|---|
| 238 | $first = true; |
|---|
| 239 | foreach($arrRow as $item){ |
|---|
| 240 | if($first) { |
|---|
| 241 | $result .= $item; |
|---|
| 242 | } else { |
|---|
| 243 | $result .= ','.$item; |
|---|
| 244 | } |
|---|
| 245 | $first = false; |
|---|
| 246 | } |
|---|
| 247 | } |
|---|
| 248 | return $result; |
|---|
| 249 | } |
|---|
| 250 | |
|---|
| 251 | private function getRowFromArray($arrRow){ |
|---|
| 252 | $result = ""; |
|---|
| 253 | if(is_array($arrRow)){ |
|---|
| 254 | foreach($arrRow as $item){ |
|---|
| 255 | $result .= $item; |
|---|
| 256 | } |
|---|
| 257 | } |
|---|
| 258 | return $result; |
|---|
| 259 | } |
|---|
| 260 | |
|---|
| 261 | private function excel_patch_num($tmp){ |
|---|
| 262 | |
|---|
| 263 | // Excel get confused..and loose precision forcing exponential |
|---|
| 264 | // if $item is numeric, but more than 15 character |
|---|
| 265 | $test = ""; |
|---|
| 266 | if ((is_numeric($tmp)=== true)) { |
|---|
| 267 | if ((strlen($tmp)>=16)) { |
|---|
| 268 | $test = "C:" . $tmp; |
|---|
| 269 | } else { |
|---|
| 270 | $test = $tmp; |
|---|
| 271 | } |
|---|
| 272 | } |
|---|
| 273 | else { |
|---|
| 274 | $test=$tmp; |
|---|
| 275 | } |
|---|
| 276 | return $test; |
|---|
| 277 | |
|---|
| 278 | } |
|---|
| 279 | } |
|---|
| 280 | ?> |
|---|