Passed
Push — master ( 62782a...a28cef )
by Marcel
04:19
created

LocalCsv::getTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Analytics
4
 *
5
 * SPDX-FileCopyrightText: 2019-2022 Marcel Scherello
6
 * SPDX-License-Identifier: AGPL-3.0-or-later
7
 */
8
9
namespace OCA\Analytics\Datasource;
10
11
use OCP\Files\IRootFolder;
0 ignored issues
show
Bug introduced by
The type OCP\Files\IRootFolder 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...
12
use OCP\Files\NotFoundException;
0 ignored issues
show
Bug introduced by
The type OCP\Files\NotFoundException 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...
13
use OCP\IL10N;
0 ignored issues
show
Bug introduced by
The type OCP\IL10N 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...
14
use Psr\Log\LoggerInterface;
0 ignored issues
show
Bug introduced by
The type Psr\Log\LoggerInterface 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...
15
use OCA\Analytics\Service\VariableService;
16
17
class LocalCsv implements IDatasource
18
{
19
    private $logger;
20
    private $rootFolder;
21
    private $userId;
22
    private $l10n;
23
    private $VariableService;
24
25
    public function __construct(
26
        $userId,
27
        IL10N $l10n,
28
        LoggerInterface $logger,
29
        IRootFolder $rootFolder,
30
        VariableService $VariableService
31
    )
32
    {
33
        $this->userId = $userId;
34
        $this->l10n = $l10n;
35
        $this->logger = $logger;
36
        $this->rootFolder = $rootFolder;
37
        $this->VariableService = $VariableService;
38
    }
39
40
    /**
41
     * @return string Display Name of the datasource
42
     */
43
    public function getName(): string
44
    {
45
        return $this->l10n->t('Local') . ': csv';
46
    }
47
48
    /**
49
     * @return int digit unique data source id
50
     */
51
    public function getId(): int
52
    {
53
        return 1;
54
    }
55
56
    /**
57
     * @return array available options of the datasoure
58
     */
59
    public function getTemplate(): array
60
    {
61
        $template = array();
62
        $template[] = ['id' => 'link', 'name' => $this->l10n->t('LocalCsv'), 'placeholder' => $this->l10n->t('LocalCsv'), 'type' => 'filePicker'];
63
        $template[] = ['id' => 'hasHeader', 'name' => $this->l10n->t('Header row'), 'placeholder' => 'true-' . $this->l10n->t('Yes').'/false-'.$this->l10n->t('No'), 'type' => 'tf'];
64
        $template[] = ['id' => 'offset', 'name' => $this->l10n->t('Ignore leading rows'), 'placeholder' => $this->l10n->t('Number of rows'), 'type' => 'number'];
65
        $template[] = ['id' => 'columns', 'name' => $this->l10n->t('Select columns'), 'placeholder' => $this->l10n->t('e.g. 1,2,4 or leave empty'), 'type' => 'columnPicker'];
66
        return $template;
67
    }
68
69
    /**
70
     * Read the Data
71
     * @param $option
72
     * @return array available options of the datasoure
73
     * @throws NotFoundException
74
     * @throws \OCP\Files\NotPermittedException
75
     */
76
    public function readData($option): array
77
    {
78
        $error = 0;
79
        $file = $this->rootFolder->getUserFolder($option['user_id'])->get($option['link']);
80
        $rows = str_getcsv($file->getContent(), "\n");
81
82
        // remove x number of rows from the beginning
83
        if (isset($option['offset']) and is_numeric($option['offset'])) {
84
            $rows = array_slice($rows, $option['offset']);
85
        }
86
87
        $selectedColumns = array();
88
        if (isset($option['columns']) && strlen($option['columns']) > 0) {
89
            $selectedColumns = str_getcsv($option['columns'], ',');
90
        }
91
92
        // get the delimiter by reading the first row
93
        $delimiter = $this->detectDelimiter($rows[0]);
94
95
        // the first row will define the column headers, even if it is not a real header
96
        // trim removes any leading or ending spaces
97
        $header = array_map('trim', str_getcsv($rows[0], $delimiter));
98
99
        // if the data has a real header, remove the first row
100
        if (!isset($option['hasHeader']) or $option['hasHeader'] !== 'false') {
101
            $rows = array_slice($rows, 1);
102
        }
103
104
        $data = array();
105
        if (count($selectedColumns) !== 0) {
106
            // if only a subset of columns or fixed column values are set, they are replaced here
107
            $header = $this->minimizeRow($selectedColumns, $header);
108
            foreach ($rows as $row) {
109
                $data[] = $this->minimizeRow($selectedColumns, array_map('trim', str_getcsv($row, $delimiter)));
110
            }
111
        } else {
112
            foreach ($rows as $row) {
113
                $data[] = array_map('trim', str_getcsv($row, $delimiter));
114
            }
115
        }
116
        unset($rows);
117
118
        return [
119
            'header' => $header,
120
            'dimensions' => array_slice($header, 0, count($header) - 1),
121
            'data' => $data,
122
            'error' => $error,
123
        ];
124
    }
125
126
    private function minimizeRow($selectedColumns, $row)
127
    {
128
        $rowMinimized = array();
129
        foreach ($selectedColumns as $selectedColumn) {
130
            if (is_numeric($selectedColumn)) {
131
                $rowMinimized[] = $row[$selectedColumn - 1];
132
            } else {
133
                // if columns contain replacement variables, they are processed here
134
                $rowMinimized[] = $this->VariableService->replaceDatasourceColumns($selectedColumn);
135
            }
136
        }
137
        return $rowMinimized;
138
    }
139
140
    private function detectDelimiter($data)
141
    {
142
        $delimiters = ["\t", ";", "|", ","];
143
        $data_2 = array();
144
        $delimiter = $delimiters[0];
145
        foreach ($delimiters as $d) {
146
            $data_1 = str_getcsv($data, $d);
147
            if (sizeof($data_1) > sizeof($data_2)) {
148
                $delimiter = $d;
149
                $data_2 = $data_1;
150
            }
151
        }
152
        return $delimiter;
153
    }
154
}