|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* Export to spreadsheet model file. |
|
5
|
|
|
* |
|
6
|
|
|
* @package Model |
|
7
|
|
|
* |
|
8
|
|
|
* @copyright YetiForce S.A. |
|
9
|
|
|
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com) |
|
10
|
|
|
* @author Mariusz Krzaczkowski <[email protected]> |
|
11
|
|
|
* @author Radosław Skrzypczak <[email protected]> |
|
12
|
|
|
*/ |
|
13
|
|
|
/** |
|
14
|
|
|
* Export to spreadsheet model class. |
|
15
|
|
|
*/ |
|
16
|
|
|
class Vtiger_ExportToSpreadsheet_Model extends \App\Export\ExportRecords |
|
17
|
|
|
{ |
|
18
|
|
|
protected $workBook; |
|
19
|
|
|
protected $workSheet; |
|
20
|
|
|
protected $headerStyles; |
|
21
|
|
|
protected $colNo = 1; |
|
22
|
|
|
protected $rowNo = 1; |
|
23
|
|
|
protected $invNo = 0; |
|
24
|
|
|
|
|
25
|
|
|
/** |
|
26
|
|
|
* Constructor. |
|
27
|
|
|
*/ |
|
28
|
|
|
public function __construct() |
|
29
|
|
|
{ |
|
30
|
|
|
parent::__construct(); |
|
31
|
|
|
$this->workBook = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); |
|
32
|
|
|
$this->workSheet = $this->workBook->setActiveSheetIndex(0); |
|
33
|
|
|
$this->headerStyles = [ |
|
34
|
|
|
'fill' => ['type' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'color' => ['argb' => 'E1E0F7']], |
|
35
|
|
|
'font' => ['bold' => true], |
|
36
|
|
|
]; |
|
37
|
|
|
} |
|
38
|
|
|
|
|
39
|
|
|
/** {@inheritdoc} */ |
|
40
|
|
|
public function getHeaders(): array |
|
41
|
|
|
{ |
|
42
|
|
|
$headers = parent::getHeaders(); |
|
43
|
|
|
foreach ($headers as $header) { |
|
44
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, $header, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); |
|
45
|
|
|
++$this->colNo; |
|
46
|
|
|
} |
|
47
|
|
|
++$this->rowNo; |
|
48
|
|
|
return $headers; |
|
49
|
|
|
} |
|
50
|
|
|
|
|
51
|
|
|
/** {@inheritdoc} */ |
|
52
|
|
|
public function output($headers, $entries) |
|
|
|
|
|
|
53
|
|
|
{ |
|
54
|
|
|
//having written out all the data lets have a go at getting the columns to auto-size |
|
55
|
|
|
$row = $col = 1; |
|
56
|
|
|
$length = \count($headers); |
|
57
|
|
|
for ($i = 1; $i <= $length; ++$i) { |
|
58
|
|
|
$cell = $this->workSheet->getCellByColumnAndRow($col, $row); |
|
59
|
|
|
$this->workSheet->getStyleByColumnAndRow($col, $row)->applyFromArray($this->headerStyles); |
|
60
|
|
|
$this->workSheet->getColumnDimension($cell->getColumn())->setAutoSize(true); |
|
61
|
|
|
++$col; |
|
62
|
|
|
} |
|
63
|
|
|
$tempFileName = tempnam(ROOT_DIRECTORY . DIRECTORY_SEPARATOR . \App\Config::main('tmp_dir'), 'xls'); |
|
64
|
|
|
$workbookWriter = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($this->workBook, ucfirst($this->fileExtension)); |
|
65
|
|
|
$workbookWriter->save($tempFileName); |
|
66
|
|
|
$fp = fopen($tempFileName, 'r'); |
|
67
|
|
|
fpassthru($fp); |
|
68
|
|
|
fclose($fp); |
|
69
|
|
|
unlink($tempFileName); |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
/** {@inheritdoc} */ |
|
73
|
|
|
public function exportData() |
|
74
|
|
|
{ |
|
75
|
|
|
$headers = $this->getHeaders(); |
|
76
|
|
|
|
|
77
|
|
|
$addInventoryData = $this->fullData && $this->moduleInstance->isInventory(); |
|
78
|
|
|
if ($addInventoryData) { |
|
79
|
|
|
$inventoryModel = Vtiger_Inventory_Model::getInstance($this->moduleName); |
|
80
|
|
|
$inventoryFields = $inventoryModel->getFields(); |
|
81
|
|
|
$inventoryTable = $inventoryModel->getDataTableName(); |
|
82
|
|
|
} |
|
83
|
|
|
$dataReader = $this->getExportQuery()->createCommand()->query(); |
|
84
|
|
|
while ($row = $dataReader->read()) { |
|
85
|
|
|
if ($addInventoryData) { |
|
86
|
|
|
$invRows = (new \App\Db\Query())->from($inventoryTable)->where(['crmid' => $row['id']])->orderBy('seq')->all(); |
|
|
|
|
|
|
87
|
|
|
if ($invRows) { |
|
88
|
|
|
foreach ($invRows as $invRow) { |
|
89
|
|
|
$this->sanitizeValues($row); |
|
90
|
|
|
$this->sanitizeInventoryValues($invRow, $inventoryFields); |
|
|
|
|
|
|
91
|
|
|
} |
|
92
|
|
|
} |
|
93
|
|
|
} else { |
|
94
|
|
|
$this->sanitizeValues($row); |
|
95
|
|
|
} |
|
96
|
|
|
} |
|
97
|
|
|
$dataReader->close(); |
|
98
|
|
|
|
|
99
|
|
|
$this->output($headers, []); |
|
100
|
|
|
} |
|
101
|
|
|
|
|
102
|
|
|
/** {@inheritdoc} */ |
|
103
|
|
|
public function sanitizeValues(array $row): array |
|
104
|
|
|
{ |
|
105
|
|
|
++$this->rowNo; |
|
106
|
|
|
$this->colNo = 1; |
|
107
|
|
|
|
|
108
|
|
|
foreach ($this->fields as $dbKey => $fieldModel) { |
|
109
|
|
|
$idKey = 'id'; |
|
110
|
|
|
if ($fieldModel->get('source_field_name')) { |
|
111
|
|
|
$name = $fieldModel->get('source_field_name') . $fieldModel->getModuleName(); |
|
112
|
|
|
$idKey = $name . $idKey; |
|
113
|
|
|
$dbKey = $name . $fieldModel->getName(); |
|
114
|
|
|
} |
|
115
|
|
|
|
|
116
|
|
|
$this->putDataIntoSpreadsheet($fieldModel, $row[$dbKey], $row[$idKey] ?? 0); |
|
117
|
|
|
} |
|
118
|
|
|
|
|
119
|
|
|
return []; |
|
120
|
|
|
} |
|
121
|
|
|
|
|
122
|
|
|
/** |
|
123
|
|
|
* Put data into spread sheet. |
|
124
|
|
|
* |
|
125
|
|
|
* @param Vtiger_Field_Model $fieldModel |
|
126
|
|
|
* @param mixed $value |
|
127
|
|
|
* @param int $id |
|
128
|
|
|
* |
|
129
|
|
|
* @return void |
|
130
|
|
|
*/ |
|
131
|
|
|
public function putDataIntoSpreadsheet(Vtiger_Field_Model $fieldModel, $value, int $id) |
|
132
|
|
|
{ |
|
133
|
|
|
switch ($fieldModel->getFieldDataType()) { |
|
134
|
|
|
case 'integer': |
|
135
|
|
|
case 'double': |
|
136
|
|
|
case 'currency': |
|
137
|
|
|
$type = is_numeric($value) ? \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC : \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING; |
|
138
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, $value, $type); |
|
139
|
|
|
break; |
|
140
|
|
|
case 'date': |
|
141
|
|
|
if ($value) { |
|
142
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel($value), \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC); |
|
143
|
|
|
$this->workSheet->getStyleByColumnAndRow($this->colNo, $this->rowNo)->getNumberFormat()->setFormatCode('DD/MM/YYYY'); |
|
144
|
|
|
} else { |
|
145
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, '', \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); |
|
146
|
|
|
} |
|
147
|
|
|
break; |
|
148
|
|
|
case 'datetime': |
|
149
|
|
|
if ($value) { |
|
150
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel($value), \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC); |
|
151
|
|
|
$this->workSheet->getStyleByColumnAndRow($this->colNo, $this->rowNo)->getNumberFormat()->setFormatCode('DD/MM/YYYY HH:MM:SS'); |
|
152
|
|
|
} else { |
|
153
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, '', \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); |
|
154
|
|
|
} |
|
155
|
|
|
break; |
|
156
|
|
|
default: |
|
157
|
|
|
$displayValue = $this->getDisplayValue($fieldModel, $value, $id, []) ?: ''; |
|
158
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, $displayValue, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); |
|
159
|
|
|
} |
|
160
|
|
|
++$this->colNo; |
|
161
|
|
|
} |
|
162
|
|
|
|
|
163
|
|
|
/** {@inheritdoc} */ |
|
164
|
|
|
public function sanitizeInventoryValues(array $inventoryRow, array $inventoryFields): array |
|
165
|
|
|
{ |
|
166
|
|
|
++$this->invNo; |
|
167
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, $this->invNo, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC); |
|
168
|
|
|
++$this->colNo; |
|
169
|
|
|
foreach ($inventoryFields as $columnName => $field) { |
|
170
|
|
|
$value = $inventoryRow[$columnName] ?? ''; |
|
171
|
|
|
if (\in_array($field->getType(), ['Name', 'Reference', 'Currency', 'Value', 'Unit', 'Boolean', 'Comment', 'Picklist', 'PicklistField', 'DiscountMode', 'TaxMode'])) { |
|
172
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, $field->getDisplayValue($value, $inventoryRow, true), \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); |
|
173
|
|
|
} elseif ('Date' === $field->getType()) { |
|
174
|
|
|
if ($value) { |
|
175
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel($value), \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC); |
|
176
|
|
|
$this->workSheet->getStyleByColumnAndRow($this->colNo, $this->rowNo)->getNumberFormat()->setFormatCode('DD/MM/YYYY'); |
|
177
|
|
|
} else { |
|
178
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, '', \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); |
|
179
|
|
|
} |
|
180
|
|
|
} else { |
|
181
|
|
|
$type = is_numeric($value) ? \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC : \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING; |
|
182
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, $value, $type); |
|
183
|
|
|
} |
|
184
|
|
|
++$this->colNo; |
|
185
|
|
|
foreach ($field->getCustomColumn() as $customColumnName => $dbType) { |
|
186
|
|
|
$valueParam = $inventoryRow[$customColumnName] ?? ''; |
|
187
|
|
|
if ('currencyparam' === $customColumnName) { |
|
188
|
|
|
$field = $inventoryFields['currency']; |
|
189
|
|
|
$valueData = $field->getCurrencyParam([], $valueParam); |
|
190
|
|
|
if (\is_array($valueData)) { |
|
191
|
|
|
$valueNewData = []; |
|
192
|
|
|
foreach ($valueData as $currencyId => $data) { |
|
193
|
|
|
$currencyName = \App\Fields\Currency::getById($currencyId)['currency_name']; |
|
194
|
|
|
$valueNewData[$currencyName] = $data; |
|
195
|
|
|
} |
|
196
|
|
|
$valueParam = \App\Json::encode($valueNewData); |
|
197
|
|
|
} |
|
198
|
|
|
} |
|
199
|
|
|
$this->workSheet->setCellValueExplicitByColumnAndRow($this->colNo, $this->rowNo, $valueParam, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); |
|
200
|
|
|
++$this->colNo; |
|
201
|
|
|
} |
|
202
|
|
|
} |
|
203
|
|
|
return []; |
|
204
|
|
|
} |
|
205
|
|
|
} |
|
206
|
|
|
|
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.