Passed
Push — master ( 3497aa...8e4611 )
by Marcel
02:45
created

VariableService::replaceTextVariablesSingle()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 13
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 19
rs 8.8333
1
<?php
2
/**
3
 * 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 2019-2022 Marcel Scherello
10
 */
11
12
namespace OCA\Analytics\Service;
13
14
use OCA\Analytics\Db\DatasetMapper;
15
use OCP\IDateTimeFormatter;
16
use Psr\Log\LoggerInterface;
17
18
class VariableService
19
{
20
    private $logger;
21
    private $DatasetMapper;
22
    private $IDateTimeFormatter;
23
24
    public function __construct(
25
        LoggerInterface $logger,
26
        DatasetMapper $DatasetMapper,
27
        IDateTimeFormatter $IDateTimeFormatter
28
    )
29
    {
30
        $this->logger = $logger;
31
        $this->DatasetMapper = $DatasetMapper;
32
        $this->IDateTimeFormatter = $IDateTimeFormatter;
33
    }
34
35
    /**
36
     * replace %*% text variables in thresholds
37
     *
38
     * @param array $thresholds
39
     * @return array
40
     */
41
    public function replaceThresholdsVariables($thresholds)
42
    {
43
        foreach ($thresholds as &$threshold) {
44
            $fields = ['dimension1', 'dimension2'];
45
            foreach ($fields as $field) {
46
                isset($threshold[$field]) ? $name = $threshold[$field] : $name = '';
47
                $parsed = $this->parseFilter($name);
48
                if (!$parsed) break;
0 ignored issues
show
Bug Best Practice introduced by
The expression $parsed of type array<string,integer|mixed|string> is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
49
                $threshold[$field] = $parsed['6$startDate'];
50
            }
51
        }
52
        return $thresholds;
53
    }
54
55
    /**
56
     * replace %*% text variables in name and subheader
57
     *
58
     * @param array $datasetMetadata
59
     * @return array
60
     */
61
    public function replaceTextVariables($datasetMetadata)
62
    {
63
        $fields = ['name', 'subheader'];
64
        foreach ($fields as $field) {
65
            isset($datasetMetadata[$field]) ? $name = $datasetMetadata[$field] : $name = '';
66
67
            preg_match_all("/%.*?%/", $name, $matches);
68
            if (count($matches[0]) > 0) {
69
                foreach ($matches[0] as $match) {
70
                    $replace = null;
71
                    if ($match === '%currentDate%') {
72
                        $replace = $this->IDateTimeFormatter->formatDate(time(), 'short');
73
                    } elseif ($match === '%currentTime%') {
74
                        $replace = $this->IDateTimeFormatter->formatTime(time(), 'short');
75
                    } elseif ($match === '%now%') {
76
                        $replace = time();
77
                    } elseif ($match === '%lastUpdateDate%') {
78
                        $timestamp = $this->DatasetMapper->getLastUpdate($datasetMetadata['dataset']);
79
                        $replace = $this->IDateTimeFormatter->formatDate($timestamp, 'short');
80
                    } elseif ($match === '%lastUpdateTime%') {
81
                        $timestamp = $this->DatasetMapper->getLastUpdate($datasetMetadata['dataset']);
82
                        $replace = $this->IDateTimeFormatter->formatTime($timestamp, 'short');
83
                    } elseif ($match === '%owner%') {
84
                        $owner = $this->DatasetMapper->getOwner($datasetMetadata['dataset']);
85
                        $replace = $owner;
86
                    }
87
                    if ($replace !== null) {
88
                        $datasetMetadata[$field] = preg_replace('/' . $match . '/', $replace, $datasetMetadata[$field]);
89
                    }
90
                }
91
            }
92
        }
93
        return $datasetMetadata;
94
    }
95
96
    /**
97
     * replace variables in single field
98
     * used in: API
99
     *
100
     * @param $field
101
     * @return array
102
     */
103
    public function replaceTextVariablesSingle($field)
104
    {
105
        preg_match_all("/%.*?%/", $field, $matches);
106
        if (count($matches[0]) > 0) {
107
            foreach ($matches[0] as $match) {
108
                $replace = null;
109
                if ($match === '%currentDate%') {
110
                    $replace = $this->IDateTimeFormatter->formatDate(time(), 'short');
111
                } elseif ($match === '%currentTime%') {
112
                    $replace = $this->IDateTimeFormatter->formatTime(time(), 'short');
113
                } elseif ($match === '%now%') {
114
                    $replace = time();
115
                }
116
                if ($replace !== null) {
117
                    $field = preg_replace('/' . $match . '/', $replace, $field);
118
                }
119
            }
120
        }
121
        return $field;
122
    }
123
124
    /**
125
     * replace variables in filters and apply format
126
     *
127
     * @param $reportMetadata
128
     * @return array
129
     */
130
    public function replaceFilterVariables($reportMetadata)
131
    {
132
        $filteroptions = json_decode($reportMetadata['filteroptions'], true);
133
        if (isset($filteroptions['filter'])) {
134
            foreach ($filteroptions['filter'] as $key => $value) {
135
                $parsed = $this->parseFilter($value['value']);
136
                $format = $this->parseFormat($value['value']);
137
138
                if (!$parsed) break;
0 ignored issues
show
Bug Best Practice introduced by
The expression $parsed of type array<string,integer|mixed|string> is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
139
                $filteroptions['filter'][$key]['option'] = $parsed['option'];
140
                $filteroptions['filter'][$key]['value'] = date($format, $parsed['value']);
141
            }
142
        }
143
        $reportMetadata['filteroptions'] = json_encode($filteroptions);
144
        return $reportMetadata;
145
    }
146
147
    /**
148
     * parsing of %*% variables
149
     *
150
     * @param $filter
151
     * @return array|bool
152
     */
153
    private function parseFilter($filter) {
154
        preg_match_all("/(?<=%).*(?=%)/", $filter, $matches);
155
        if (count($matches[0]) > 0) {
156
            $filter = $matches[0][0];
157
            preg_match('/(last|next|current|to|yester)?/', $filter, $directionMatch); // direction
158
            preg_match('/[0-9]+/', $filter, $offsetMatch); // how much
159
            preg_match('/(day|days|week|weeks|month|months|year|years)$/', $filter, $unitMatch); // unit
160
161
            if (!$directionMatch[0] || !$unitMatch[0]) {
162
                // no known text variables found
163
                return false;
164
            }
165
166
            // if no offset is specified, apply 1 as default
167
            !$offsetMatch[0] ? $offset = 1: $offset = $offsetMatch[0];
168
169
            // remove "s" to unify e.g. weeks => week
170
            $unit = rtrim($unitMatch[0], 's');
171
172
            if ($directionMatch[0] === "last" || $directionMatch[0] === "yester") {
173
                // go back
174
                $direction = '-';
175
            } elseif ($directionMatch[0] === "next") {
176
                // go forward
177
                $direction = '+';
178
            } else {
179
                // current
180
                $direction = '+';
181
                $offset = 0;
182
            }
183
184
            // create a usable string for php like "+3 days"
185
            $timeString = $direction . $offset . ' ' . $unit;
186
            // get a timestamp of the target date
187
            $baseDate = strtotime($timeString);
188
189
            // get the correct format depending of the unit. e.g. first day of the month in case unit is "month"
190
            if ($unit === 'day') {
191
                $startString = 'today';
192
            } else {
193
                $startString = 'first day of this ' . $unit;
194
            }
195
            $startTS = strtotime($startString, $baseDate);
196
            $start = date("Y-m-d", $startTS);
197
198
            $return = [
199
                'value' => $startTS,
200
                'option' => 'GT',
201
                '1$filter' => $filter,
202
                '2$timestring' => $timeString,
203
                '3$target' => $baseDate,
204
                '4$target_clean' => date("Y-m-d", $baseDate),
205
                '5$startString' => $startString,
206
                '6$startDate' => $start,
207
                '7$startTS' => $startTS,
208
           ];
209
        } else {
210
            $return = false;
211
        }
212
        return $return;
213
    }
214
215
    /**
216
     * parsing of ( ) format instructions
217
     *
218
     * @param $filter
219
     * @return string
220
     */
221
    private function parseFormat($filter) {
222
        preg_match_all("/(?<=\().*(?=\))/", $filter, $matches);
223
        if (count($matches[0]) > 0) {
224
            return $matches[0][0];
225
        } else {
226
            return 'Y-m-d H:m:s';
227
        }
228
    }
229
}