Passed
Push — master ( 1d1c0d...40ae07 )
by Marcel
02:46
created

DataloadController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 10
dl 0
loc 22
rs 9.9666
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * Data Analytics
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the LICENSE.md file.
7
 *
8
 * @author Marcel Scherello <[email protected]>
9
 * @copyright 2020 Marcel Scherello
10
 */
11
12
namespace OCA\Analytics\Controller;
13
14
use Exception;
15
use OCA\Analytics\Activity\ActivityManager;
16
use OCA\Analytics\Db\DataloadMapper;
17
use OCP\AppFramework\Controller;
18
use OCP\AppFramework\Http\DataResponse;
19
use OCP\AppFramework\Http\NotFoundResponse;
20
use OCP\Files\NotFoundException;
21
use OCP\IL10N;
22
use OCP\ILogger;
23
use OCP\IRequest;
24
25
class DataloadController extends Controller
26
{
27
    private $logger;
28
    private $StorageController;
29
    private $DataSourceController;
30
    private $userId;
31
    private $ActivityManager;
32
    private $DatasetController;
33
    private $l10n;
34
    private $DataloadMapper;
35
36
    public function __construct(
37
        string $AppName,
38
        IRequest $request,
39
        IL10N $l10n,
40
        $userId,
41
        ILogger $logger,
42
        ActivityManager $ActivityManager,
43
        DataSourceController $DataSourceController,
44
        DatasetController $DatasetController,
45
        StorageController $StorageController,
46
        DataloadMapper $DataloadMapper
47
    )
48
    {
49
        parent::__construct($AppName, $request);
50
        $this->l10n = $l10n;
51
        $this->userId = $userId;
52
        $this->logger = $logger;
53
        $this->StorageController = $StorageController;
54
        $this->ActivityManager = $ActivityManager;
55
        $this->DataSourceController = $DataSourceController;
56
        $this->DatasetController = $DatasetController;
57
        $this->DataloadMapper = $DataloadMapper;
58
    }
59
60
    // Dataloads
61
    // Dataloads
62
    // Dataloads
63
64
    /**
65
     * create a new dataload
66
     *
67
     * @NoAdminRequired
68
     * @param int $datasetId
69
     * @param int $datasourceId
70
     * @return DataResponse
71
     */
72
    public function create(int $datasetId, int $datasourceId)
73
    {
74
        return new DataResponse(['id' => $this->DataloadMapper->create($datasetId, $datasourceId)]);
75
    }
76
77
    /**
78
     * get all dataloads for a dataset
79
     *
80
     * @NoAdminRequired
81
     * @param int $datasetId
82
     * @return DataResponse
83
     */
84
    public function read(int $datasetId)
85
    {
86
        $result = array();
87
        $result['dataloads'] = $this->DataloadMapper->read($datasetId);
88
        $result['templates'] = $this->DataSourceController->getTemplates();
89
        return new DataResponse($result);
90
    }
91
92
    /**
93
     * update dataload
94
     *
95
     * @NoAdminRequired
96
     * @param int $dataloadId
97
     * @param $name
98
     * @param $option
99
     * @param $schedule
100
     * @return DataResponse
101
     */
102
    public function update(int $dataloadId, $name, $option, $schedule)
103
    {
104
        return new DataResponse(['update' => $this->DataloadMapper->update($dataloadId, $name, $option, $schedule)]);
105
    }
106
107
    /**
108
     * delete a dataload
109
     *
110
     * @NoAdminRequired
111
     * @param int $dataloadId
112
     * @return bool
113
     */
114
    public function delete(int $dataloadId)
115
    {
116
        return $this->DataloadMapper->delete($dataloadId);
117
    }
118
119
    /**
120
     * simulate a dataload and output its data
121
     *
122
     * @NoAdminRequired
123
     * @param int $dataloadId
124
     * @return DataResponse
125
     * @throws NotFoundException
126
     */
127
    public function simulate(int $dataloadId)
128
    {
129
        $result = $this->getDataFromDatasource($dataloadId);
130
        return new DataResponse($result);
131
    }
132
133
    /**
134
     * execute all dataloads depending on their schedule
135
     * daily or hourly
136
     *
137
     * @NoAdminRequired
138
     * @param $schedule
139
     * @return void
140
     * @throws Exception
141
     */
142
    public function executeBySchedule($schedule)
143
    {
144
        $schedules = $this->DataloadMapper->getDataloadBySchedule($schedule);
145
        //$this->logger->debug('DataLoadController 145: execute schedule '.$schedule);
146
        foreach ($schedules as $dataload) {
147
            //$this->logger->debug('DataLoadController 147: execute dataload '.$dataload['id']);
148
            $this->execute($dataload['id']);
149
        }
150
    }
151
152
    /**
153
     * execute a dataload from datasource and store into dataset
154
     *
155
     * @NoAdminRequired
156
     * @param int $dataloadId
157
     * @return DataResponse
158
     * @throws Exception
159
     */
160
    public function execute(int $dataloadId)
161
    {
162
        //$this->logger->debug('DataLoadController 143:'.$dataloadId);
163
        $dataloadMetadata = $this->DataloadMapper->getDataloadById($dataloadId);
164
        $result = $this->getDataFromDatasource($dataloadId);
165
        $insert = $update = 0;
166
        $datasetId = $result['datasetId'];
167
        //$this->logger->debug('DataLoadController 146: loading into dataset '.$datasetId);
168
169
        if ($result['error'] === 0) {
170
            //$this->logger->debug('DataLoadController 149: OK');
171
            foreach ($result['data'] as &$row) {
172
                $action = $this->StorageController->update($datasetId, $row['dimension1'], $row['dimension2'], $row['dimension3'], $dataloadMetadata['user_id']);
173
                $insert = $insert + $action['insert'];
174
                $update = $update + $action['update'];
175
            }
176
        }
177
178
        $result = [
179
            'insert' => $insert,
180
            'update' => $update,
181
            'error' => $result['error'],
182
        ];
183
184
        if ($result['error'] === 0) $this->ActivityManager->triggerEvent($datasetId, ActivityManager::OBJECT_DATA, ActivityManager::SUBJECT_DATA_ADD_DATALOAD, $dataloadMetadata['user_id']);
185
186
        return new DataResponse($result);
187
    }
188
189
    /**
190
     * get the data from datasource
191
     * to be used in simulation or execution
192
     *
193
     * @NoAdminRequired
194
     * @param int $dataloadId
195
     * @return array|NotFoundResponse
196
     * @throws NotFoundException
197
     */
198
    private function getDataFromDatasource(int $dataloadId)
199
    {
200
        $dataloadMetadata = $this->DataloadMapper->getDataloadById($dataloadId);
201
        $datasetMetadata = $this->DatasetController->getOwnDataset($dataloadMetadata['dataset'], $dataloadMetadata['user_id']);
202
203
        if (!empty($datasetMetadata)) {
204
            $option = json_decode($dataloadMetadata['option'], true);
205
            $option['user_id'] = $dataloadMetadata['user_id'];
206
207
            //$this->logger->debug('DataLoadController 187: ' . $dataloadMetadata['option'] . '---' . json_encode($option));
208
            $result = $this->DataSourceController->read((int)$dataloadMetadata['datasource'], $option);
209
            $result['datasetId'] = $dataloadMetadata['dataset'];
210
211
            if (isset($option['timestamp']) and $option['timestamp'] === 'true') {
212
                // if datasource should be timestamped/snapshoted
213
                // shift values by one dimension
214
                $result['data'] = array_map(function ($tag) {
215
                    return array(
216
                        'dimension1' => $tag['dimension2'],
217
                        'dimension2' => $tag['dimension2'],
218
                        'dimension3' => $tag['dimension3']
219
                    );
220
                }, $result['data']);
221
                $result['data'] = $this->replaceDimension($result['data'], 'dimension2', date("Y-m-d H:i:s"));
222
            }
223
224
            return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result returns the type OCP\Files\NotFoundException which is incompatible with the documented return type OCP\AppFramework\Http\NotFoundResponse|array.
Loading history...
225
        } else {
226
            return new NotFoundResponse();
227
        }
228
    }
229
230
    /**
231
     * replace all values of one dimension
232
     *
233
     * @NoAdminRequired
234
     * @param $Array
235
     * @param $Find
236
     * @param $Replace
237
     * @return array
238
     */
239
    private function replaceDimension($Array, $Find, $Replace)
240
    {
241
        if (is_array($Array)) {
242
            foreach ($Array as $Key => $Val) {
243
                if (is_array($Array[$Key])) {
244
                    $Array[$Key] = $this->replaceDimension($Array[$Key], $Find, $Replace);
245
                } else {
246
                    if ($Key == $Find) {
247
                        $Array[$Key] = $Replace;
248
                    }
249
                }
250
            }
251
        }
252
        return $Array;
253
    }
254
255
    // Data Manipulation
256
    // Data Manipulation
257
    // Data Manipulation
258
259
    /**
260
     * update data from input form
261
     *
262
     * @NoAdminRequired
263
     * @param int $datasetId
264
     * @param $dimension1
265
     * @param $dimension2
266
     * @param $dimension3
267
     * @return DataResponse|NotFoundResponse
268
     * @throws Exception
269
     */
270
    public function updateData(int $datasetId, $dimension1, $dimension2, $dimension3)
271
    {
272
        $datasetMetadata = $this->DatasetController->getOwnDataset($datasetId);
273
        if (!empty($datasetMetadata)) {
274
            $insert = $update = $errorMessage = 0;
275
            $action = array();
276
            $dimension3 = $this->floatvalue($dimension3);
277
            if ($dimension3 === false) {
278
                $errorMessage = $this->l10n->t('3rd field must be a valid number');
279
            } else {
280
                $action = $this->StorageController->update($datasetId, $dimension1, $dimension2, $dimension3);
281
                $insert = $insert + $action['insert'];
282
                $update = $update + $action['update'];
283
            }
284
285
            $result = [
286
                'insert' => $insert,
287
                'update' => $update,
288
                'error' => $errorMessage,
289
                'validate' => $action['validate'],
290
            ];
291
292
            //$this->logger->error('DataLoadController 88:'.$errorMessage);
293
            if ($errorMessage === 0) $this->ActivityManager->triggerEvent($datasetId, ActivityManager::OBJECT_DATA, ActivityManager::SUBJECT_DATA_ADD);
294
            return new DataResponse($result);
295
        } else {
296
            return new NotFoundResponse();
297
        }
298
    }
299
300
    /**
301
     * delete data from input form
302
     *
303
     * @NoAdminRequired
304
     * @param int $datasetId
305
     * @param $dimension1
306
     * @param $dimension2
307
     * @return DataResponse|NotFoundResponse
308
     */
309
    public function deleteData(int $datasetId, $dimension1, $dimension2)
310
    {
311
        $datasetMetadata = $this->DatasetController->getOwnDataset($datasetId);
312
        if (!empty($datasetMetadata)) {
313
            $result = $this->StorageController->delete($datasetId, $dimension1, $dimension2);
314
            return new DataResponse(['delete' => $result]);
315
        } else {
316
            return new NotFoundResponse();
317
        }
318
    }
319
320
    /**
321
     * Simulate delete data from input form
322
     *
323
     * @NoAdminRequired
324
     * @param int $datasetId
325
     * @param $dimension1
326
     * @param $dimension2
327
     * @param $dimension3
328
     * @return DataResponse|NotFoundResponse
329
     */
330
    public function deleteDataSimulate(int $datasetId, $dimension1, $dimension2, $dimension3)
331
    {
332
        $datasetMetadata = $this->DatasetController->getOwnDataset($datasetId);
333
        if (!empty($datasetMetadata)) {
334
            $result = $this->StorageController->deleteSimulate($datasetId, $dimension1, $dimension2, $dimension3);
335
            return new DataResponse(['delete' => $result]);
336
        } else {
337
            return new NotFoundResponse();
338
        }
339
    }
340
341
    /**
342
     * Import clipboard data
343
     *
344
     * @NoAdminRequired
345
     * @param int $datasetId
346
     * @param $import
347
     * @return DataResponse|NotFoundResponse
348
     * @throws Exception
349
     */
350
    public function importClipboard($datasetId, $import)
351
    {
352
        $datasetMetadata = $this->DatasetController->getOwnDataset($datasetId);
353
        if (!empty($datasetMetadata)) {
354
            $insert = $update = $errorMessage = $errorCounter = 0;
355
            $delimiter = $this->detectDelimiter($import);
356
            $rows = str_getcsv($import, "\n");
357
358
            foreach ($rows as &$row) {
359
                $row = str_getcsv($row, $delimiter);
360
                $row[2] = $this->floatvalue($row[2]);
361
                if ($row[2] === false) {
362
                    $errorCounter++;
363
                } else {
364
                    $action = $this->StorageController->update($datasetId, $row[0], $row[1], $row[2]);
365
                    $insert = $insert + $action['insert'];
366
                    $update = $update + $action['update'];
367
                }
368
                if ($errorCounter === 2) {
369
                    // first error is ignored; might be due to header row
370
                    $errorMessage = $this->l10n->t('3rd field must be a valid number');
371
                    break;
372
                }
373
            }
374
375
            $result = [
376
                'insert' => $insert,
377
                'update' => $update,
378
                'delimiter' => $delimiter,
379
                'error' => $errorMessage,
380
            ];
381
382
            if ($errorMessage === 0) $this->ActivityManager->triggerEvent($datasetId, ActivityManager::OBJECT_DATA, ActivityManager::SUBJECT_DATA_ADD_IMPORT);
383
            return new DataResponse($result);
384
        } else {
385
            return new NotFoundResponse();
386
        }
387
    }
388
389
    /**
390
     * Import data into dataset from an internal or external file
391
     *
392
     * @NoAdminRequired
393
     * @param int $datasetId
394
     * @param $path
395
     * @return DataResponse|NotFoundResponse
396
     * @throws NotFoundException
397
     * @throws Exception
398
     */
399
    public function importFile(int $datasetId, $path)
400
    {
401
        $this->logger->error('DataLoadController 378:' . $datasetId . $path);
402
        $datasetMetadata = $this->DatasetController->getOwnDataset($datasetId);
403
        if (!empty($datasetMetadata)) {
404
            $insert = $update = 0;
405
            $option = array();
406
            $option['user_id'] = $datasetMetadata['user_id'];
407
            $option['path'] = $path;
408
            $option['link'] = $datasetMetadata['link'];
409
            $result = $this->DataSourceController->read(DataSourceController::DATASET_TYPE_INTERNAL_FILE, $option);
410
411
            if ($result['error'] === 0) {
412
                foreach ($result['data'] as &$row) {
413
                    $action = $this->StorageController->update($datasetId, $row['dimension1'], $row['dimension2'], $row['dimension3']);
414
                    $insert = $insert + $action['insert'];
415
                    $update = $update + $action['update'];
416
                }
417
            }
418
419
            $result = [
420
                'insert' => $insert,
421
                'update' => $update,
422
                'error' => $result['error'],
423
            ];
424
425
            if ($result['error'] === 0) $this->ActivityManager->triggerEvent($datasetId, ActivityManager::OBJECT_DATA, ActivityManager::SUBJECT_DATA_ADD_IMPORT);
426
            return new DataResponse($result);
427
        } else {
428
            return new NotFoundResponse();
429
        }
430
    }
431
432
    private function detectDelimiter($data)
433
    {
434
        $delimiters = ["\t", ";", "|", ","];
435
        $data_2 = null;
436
        $delimiter = $delimiters[0];
437
        foreach ($delimiters as $d) {
438
            $firstRow = str_getcsv($data, "\n")[0];
439
            $data_1 = str_getcsv($firstRow, $d);
440
            if (sizeof($data_1) > sizeof($data_2)) {
441
                $delimiter = $d;
442
                $data_2 = $data_1;
443
            }
444
        }
445
        return $delimiter;
446
    }
447
448
    private function floatvalue($val)
449
    {
450
        $val = str_replace(",", ".", $val);
451
        $val = preg_replace('/\.(?=.*\.)/', '', $val);
452
        $val = preg_replace('/[^0-9-.]+/', '', $val);
453
        if (is_numeric($val)) {
454
            return number_format(floatval($val), 2, '.', '');
455
        } else {
456
            return false;
457
        }
458
    }
459
}