Test Failed
Push — master ( c31487...4cc4d5 )
by Daniel
01:56
created

IOExcel::checkInputFeatures()   B

Complexity

Conditions 8
Paths 30

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 17
nc 30
nop 1
dl 0
loc 23
rs 8.4444
c 0
b 0
f 0
1
<?php
2
3
/**
4
 *
5
 * The MIT License (MIT)
6
 *
7
 * Copyright (c) 2015 - 2018 Daniel Popiniuc
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy
10
 * of this software and associated documentation files (the "Software"), to deal
11
 * in the Software without restriction, including without limitation the rights
12
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 * copies of the Software, and to permit persons to whom the Software is
14
 * furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in all
17
 * copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
 * SOFTWARE.
26
 *
27
 */
28
29
namespace danielgp\IOExcel;
30
31
/**
32
 * Description of IOExcel
33
 *
34
 * @author Daniel Popiniuc
35
 */
36
trait IOExcel
37
{
38
39
    private $objPHPExcel;
40
41
    /**
42
     * manages further inputs checks
43
     *
44
     * @param array $inFeatures Predefined array of attributes
45
     * @return arrray
0 ignored issues
show
Bug introduced by
The type danielgp\IOExcel\arrray was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
46
     */
47
    private function checkInputFeatureContent($inFeaturesWorksheets)
48
    {
49
        $aReturn = [];
50
        foreach ($inFeaturesWorksheets as $key => $value) {
51
            if (!array_key_exists('Name', $value)) {
52
                $aReturn[] = sprintf($check['4'], $key);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $check seems to be never defined.
Loading history...
53
            } elseif (!is_string($value['Name'])) {
54
                $aReturn[] = sprintf($check['4.1'], $key);
55
            }
56
            if (!array_key_exists('Content', $value)) {
57
                $aReturn[] = sprintf($check['5'], $key);
58
            } elseif (!is_array($value['Content'])) {
59
                $aReturn[] = sprintf($check['5.1'], $key);
60
            }
61
        }
62
        return $aReturn;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $aReturn returns the type array|string[] which is incompatible with the documented return type danielgp\IOExcel\arrray.
Loading history...
63
    }
64
65
    /**
66
     * manages the inputs checks
67
     *
68
     * @param array $inFeatures Predefined array of attributes
69
     * @return arrray
70
     */
71
    private function checkInputFeatures(array $inFeatures)
72
    {
73
        $aReturn = [];
74
        $check   = $this->internalCheckingErrorMessages();
75
        if ($inFeatures === []) {
76
            $aReturn[] = $check['1'];
77
        }
78
        if (!array_key_exists('Filename', $inFeatures)) {
79
            $aReturn[] = $check['2'];
80
        } elseif (!is_string($inFeatures['Filename'])) {
81
            $aReturn[] = $check['2.1'];
82
        }
83
        if (!array_key_exists('Worksheets', $inFeatures)) {
84
            $aReturn[] = $check['3'];
85
        } elseif (!is_array($inFeatures['Worksheets'])) {
86
            $aReturn[] = $check['3.1'];
87
        } elseif (array_key_exists('Worksheets', $inFeatures)) {
88
            $bReturn = $this->checkInputFeatureContent($inFeatures['Worksheets']);
89
            if ($bReturn !== []) {
0 ignored issues
show
introduced by
The condition $bReturn !== array() is always true.
Loading history...
90
                $aReturn = array_merge($aReturn, $bReturn);
0 ignored issues
show
Bug introduced by
$bReturn of type danielgp\IOExcel\arrray is incompatible with the type null|array expected by parameter $array2 of array_merge(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

90
                $aReturn = array_merge($aReturn, /** @scrutinizer ignore-type */ $bReturn);
Loading history...
91
            }
92
        }
93
        return $aReturn;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $aReturn returns the type array|string[] which is incompatible with the documented return type danielgp\IOExcel\arrray.
Loading history...
94
    }
95
96
    public function internalCheckingErrorMessages()
97
    {
98
        return [
99
            '1'   => 'Check 1: Missing parameters!',
100
            '2'   => 'Check 2: No filename provided!',
101
            '2.1' => 'Check 2.1: Provided filename is not a string!',
102
            '3'   => 'Check 3: No worksheets provided!',
103
            '3.1' => 'Check 3.1: Provided worksheets is not an array!',
104
            '4'   => 'Check 4: No Name was provided for the worksheet #%s !',
105
            '4.1' => 'Check 4.1: The Name provided for the worksheet #%s is not a string!',
106
            '5'   => 'Check 5: No Content was provided for the worksheet #%s !',
107
            '5.1' => 'Check 5.1: The Content provided for the worksheet #%s is not an array!',
108
        ];
109
    }
110
111
    /**
112
     * Generate an Excel file from a given array
113
     *
114
     * @param array $inFeatures Predefined array of attributes
115
     */
116
    public function setArrayToExcel(array $inFeatures)
117
    {
118
        $checkInputs = $this->checkInputFeatures($inFeatures);
119
        if ($checkInputs != []) {
0 ignored issues
show
introduced by
The condition $checkInputs != array() is always true.
Loading history...
120
            throw new \PhpOffice\PhpSpreadsheet\Exception(implode(', ', array_values($checkInputs)));
0 ignored issues
show
Bug introduced by
$checkInputs of type danielgp\IOExcel\arrray is incompatible with the type array expected by parameter $input of array_values(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

120
            throw new \PhpOffice\PhpSpreadsheet\Exception(implode(', ', array_values(/** @scrutinizer ignore-type */ $checkInputs)));
Loading history...
121
        }
122
        $this->objPHPExcel = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
123
        if (isset($inFeatures['Properties'])) {
124
            $this->setExcelProperties($inFeatures['Properties']);
125
        }
126
        foreach ($inFeatures['Worksheets'] as $key => $wkValue) {
127
            if ($key > 0) {
128
                $this->objPHPExcel->createSheet();
129
            }
130
            $this->objPHPExcel->setActiveSheetIndex($key);
131
            $this->objPHPExcel->getActiveSheet()->setTitle($wkValue['Name']);
132
            foreach ($wkValue['Content'] as $cntValue) {
133
                $rowIndex = $cntValue['StartingRowIndex'];
134
                foreach ($cntValue['ContentArray'] as $key2 => $value) {
135
                    if ($key2 == 0) {
136
                        $this->setExcelHeaderCellContent([
137
                            'StartingColumnIndex' => $cntValue['StartingColumnIndex'],
138
                            'StartingRowIndex'    => $rowIndex,
139
                            'RowValues'           => array_keys($value),
140
                        ]);
141
                    }
142
                    $this->setExcelRowCellContent([
143
                        'StartingColumnIndex' => $cntValue['StartingColumnIndex'],
144
                        'CurrentRowIndex'     => ($rowIndex + 1),
145
                        'RowValues'           => $value,
146
                    ]);
147
                    $rowIndex++;
148
                }
149
            }
150
            $this->setExcelWorksheetPagination();
151
            $this->setExcelWorksheetUsability([
152
                'StartingColumnIndex' => $cntValue['StartingColumnIndex'],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $cntValue does not seem to be defined for all execution paths leading up to this point.
Loading history...
153
                'HeaderRowIndex'      => $cntValue['StartingRowIndex'],
154
            ]);
155
        }
156
        $this->objPHPExcel->setActiveSheetIndex(0);
157
        $inFeatures['Filename'] = filter_var($inFeatures['Filename'], FILTER_SANITIZE_STRING);
158
        if (!in_array(PHP_SAPI, ['cli', 'cli-server'])) { // output created content to browser OR skip-it otherwise
159
            $this->setForcedHeadersWhenNotCli($inFeatures['Filename']);
160
        }
161
        $objWriter = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($this->objPHPExcel);
162
        if (in_array(PHP_SAPI, ['cli', 'cli-server'])) {
163
            $objWriter->save($inFeatures['Filename']);
164
        } else {
165
            $objWriter->save('php://output');
166
        }
167
        unset($this->objPHPExcel);
168
    }
169
170
    /**
171
     * Outputs the header cells
172
     *
173
     * @param array $inputs
174
     */
175
    private function setExcelHeaderCellContent(array $inputs)
176
    {
177
        $columnCounter = $inputs['StartingColumnIndex'];
178
        foreach ($inputs['RowValues'] as $value2) {
179
            $crtCol = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($columnCounter);
180
            $this->objPHPExcel
181
                ->getActiveSheet()
182
                ->getColumnDimension($crtCol)
183
                ->setAutoSize(true);
184
            $this->objPHPExcel
185
                ->getActiveSheet()
186
                ->setCellValue($crtCol . $inputs['StartingRowIndex'], $value2);
187
            $this->objPHPExcel
188
                ->getActiveSheet()
189
                ->getStyle($crtCol . $inputs['StartingRowIndex'])
190
                ->getFill()
191
                ->applyFromArray([
192
                    'type'       => 'solid',
193
                    'startcolor' => ['rgb' => 'CCCCCC'],
194
                    'endcolor'   => ['rgb' => 'CCCCCC'],
195
            ]);
196
            $this->objPHPExcel
197
                ->getActiveSheet()
198
                ->getStyle($crtCol . $inputs['StartingRowIndex'])
199
                ->applyFromArray([
200
                    'font' => [
201
                        'bold'  => true,
202
                        'color' => ['rgb' => '000000'],
203
                    ]
204
                    ]
205
            );
206
            $columnCounter++;
207
        }
208
        $this->objPHPExcel
209
            ->getActiveSheet()
210
            ->calculateColumnWidths();
211
    }
212
213
    /**
214
     * sets the Properties for the Excel file
215
     *
216
     * @param array $inProperties
217
     */
218
    private function setExcelProperties(array $inProperties)
219
    {
220
        if (array_key_exists('Creator', $inProperties)) {
221
            $this->objPHPExcel->getProperties()->setCreator($inProperties['Creator']);
222
        }
223
        if (array_key_exists('LastModifiedBy', $inProperties)) {
224
            $this->objPHPExcel->getProperties()->setLastModifiedBy($inProperties['LastModifiedBy']);
225
        }
226
        if (array_key_exists('description', $inProperties)) {
227
            $this->objPHPExcel->getProperties()->setDescription($inProperties['description']);
228
        }
229
        if (array_key_exists('subject', $inProperties)) {
230
            $this->objPHPExcel->getProperties()->setSubject($inProperties['subject']);
231
        }
232
        if (array_key_exists('title', $inProperties)) {
233
            $this->objPHPExcel->getProperties()->setTitle($inProperties['title']);
234
        }
235
    }
236
237
    /**
238
     * Outputs the content cells
239
     *
240
     * @param array $inputs
241
     */
242
    private function setExcelRowCellContent(array $inputs)
243
    {
244
        $columnCounter = $inputs['StartingColumnIndex'];
245
        foreach ($inputs['RowValues'] as $value2) {
246
            $crCol          = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($columnCounter);
247
            $this->objPHPExcel
248
                ->getActiveSheet()
249
                ->getColumnDimension($crCol)
250
                ->setAutoSize(false);
251
            $crtCellAddress = $crCol . $inputs['CurrentRowIndex'];
252
            $cntLen         = strlen($value2);
253
            if (($value2 == '') || ($value2 == '00:00:00') || ($value2 == '0')) {
254
                $value2 = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $value2 is dead and can be removed.
Loading history...
255
            } elseif (in_array($cntLen, [7, 8, 9]) && (($cntLen - strlen(str_replace(':', '', $value2))) == 2)) {
256
                $this->objPHPExcel
257
                    ->getActiveSheet()
258
                    ->SetCellValue($crtCellAddress, ($this->setLocalTime2Seconds($value2) / 60 / 60 / 24));
259
                $this->objPHPExcel
260
                    ->getActiveSheet()
261
                    ->getStyle($crtCellAddress)
262
                    ->getNumberFormat()
263
                    ->setFormatCode(\PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DATETIME);
264
            } else {
265
                $this->objPHPExcel
266
                    ->getActiveSheet()
267
                    ->SetCellValue($crtCellAddress, strip_tags($value2));
268
            }
269
            $columnCounter += 1;
270
        }
271
    }
272
273
    /**
274
     * sets the Pagination
275
     *
276
     */
277
    private function setExcelWorksheetPagination()
278
    {
279
        $this->objPHPExcel->getActiveSheet()->getPageSetup()->setOrientation('portrait');
280
        $this->objPHPExcel->getActiveSheet()->getPageSetup()->setPaperSize(9); //coresponding to A4
281
        $margin = 0.7 / 2.54; // margin is set in inches (0.7cm)
282
        $this->objPHPExcel->getActiveSheet()->getPageMargins()->setHeader($margin);
283
        $this->objPHPExcel->getActiveSheet()->getPageMargins()->setTop($margin * 2);
284
        $this->objPHPExcel->getActiveSheet()->getPageMargins()->setBottom($margin);
285
        $this->objPHPExcel->getActiveSheet()->getPageMargins()->setLeft($margin);
286
        $this->objPHPExcel->getActiveSheet()->getPageMargins()->setRight($margin);
287
        // add header content
288
        $this->objPHPExcel->getActiveSheet()->getHeaderFooter()->setOddHeader('&L&F&RPage &P / &N');
289
        $this->objPHPExcel->getActiveSheet()->setPrintGridlines(true); // activate printing of gridlines
290
    }
291
292
    /**
293
     * Sets a few usability features
294
     *
295
     * @param array $inputs
296
     */
297
    private function setExcelWorksheetUsability($inputs)
298
    {
299
        // repeat coloumn headings for every new page...
300
        $this->objPHPExcel
301
            ->getActiveSheet()
302
            ->getPageSetup()
303
            ->setRowsToRepeatAtTopByStartAndEnd(1, $inputs['HeaderRowIndex']);
304
        // activate AutoFilter
305
        $autoFilterArea = implode('', [
306
            \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($inputs['StartingColumnIndex']),
307
            $inputs['HeaderRowIndex'],
308
            ':',
309
            $this->objPHPExcel->getActiveSheet()->getHighestDataColumn(),
310
            $this->objPHPExcel->getActiveSheet()->getHighestDataRow(),
311
        ]);
312
        $this->objPHPExcel
313
            ->getActiveSheet()
314
            ->setAutoFilter($autoFilterArea);
315
        // freeze 1st top row
316
        $this->objPHPExcel
317
            ->getActiveSheet()
318
            ->freezePane('A' . ($inputs['HeaderRowIndex'] + 1));
319
    }
320
321
    private function setForcedHeadersWhenNotCli($strFileName)
322
    {
323
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
324
        header('Pragma: private');
325
        header('Cache-control: private, must-revalidate');
326
        header('Content-Disposition: attachment;filename="' . $strFileName . '"');
327
        header('Cache-Control: max-age=0');
328
    }
329
330
    /**
331
     * Converts the time string given into native Excel format (number)
332
     *
333
     * @param string $RSQLtime
334
     * @return string
335
     */
336
    private function setLocalTime2Seconds($RSQLtime)
337
    {
338
        $sign = '';
339
        if (is_null($RSQLtime) || ($RSQLtime == '')) {
340
            $RSQLtime = '00:00:00';
341
        } elseif (substr($RSQLtime, 0, 1) == '-') {
342
            //extract negative sign and keep it separatly until ending
343
            $RSQLtime = substr($RSQLtime, 1, strlen($RSQLtime) - 1);
344
            $sign     = '-';
345
        }
346
        $resultParts = [
347
            'seconds' => substr($RSQLtime, -2),
348
            'minutes' => substr($RSQLtime, -5, 2) * 60,
349
            'hours'   => substr($RSQLtime, 0, strlen($RSQLtime) - 6) * 60 * 60,
350
        ];
351
        return $sign . implode('', array_values($resultParts));
352
    }
353
}
354