Meta::getIndex()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the ReportBundle package
5
 *
6
 * (c) symball <http://simonball.me>
7
 *
8
 * For the full copyright and license information, please view the LICENSE file
9
 * that was distributed with this source code.
10
 */
11
12
13
namespace Symball\ReportBundle\Service;
14
15
/**
16
 * The meta service acts as a data broker in which the column headings, data
17
 * points and various options are handled
18
 *
19
 * @author Simon Ball <simonball at simonball dot me>
20
 */
21
class Meta
22
{
23
24
    protected $dataPoints = array();
25
    protected $currentDataPoint;
26
    protected $currentDataSet = array();
27
    protected $dataPointMeta;
28
    protected $options = array(
29
        'default_bg_color' => 'e9e9e9',
30
        'default_line_thickness' => 'thick',
31
        'positive_color' => 'd8ffb7',
32
        'negative_color' => 'ffc56c',
33
    );
34
    private $columnCount = 0;
35
36
    /**
37
     * Define an option and its value.
38
     *
39
     * @param string $key
40
     * @param mixed  $value
41
     * @return $this For method chaining
42
     * @throws \InvalidArgumentException if key type is not a string or integer
43
     */
44 View Code Duplication
    public function setOption($key, $value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
45
    {
46
        if (is_int($key) || is_string($key)) {
47
            $this->options[$key] = $value;
48
        } else {
49
            throw new \InvalidArgumentException('Option key must be an integer or string. ' . gettype($key) . ' given');
50
        }
51
52
        return $this;
53
    }
54
55
    /**
56
     * Set a group of options at the same time
57
     *
58
     * @param array $options
59
     * @return $this For method chaining
60
     * @throws \InvalidArgumentException If input is not an array
61
     */
62 View Code Duplication
    public function setOptions($options)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
63
    {
64
        if (is_array($options)) {
65
            $this->options = array_merge($this->options, $options);
66
        } else {
67
            throw new \InvalidArgumentException('Options must be an array. ' . gettype($options) . ' given');
68
        }
69
70
        return $this;
71
    }
72
73
    /**
74
     * Get the value of a single option or return false if it doesn't exist
75
     *
76
     * @param string|integer $key
77
     * @return string|integer|boolean The option value
78
     */
79
    public function getOption($key)
80
    {
81
        if ($key && isset($this->options[$key])) {
82
            return $this->options[$key];
83
        }
84
    }
85
86
    /**
87
     * Retrieve the full option array
88
     *
89
     * @return array
90
     */
91
    public function getOptions()
92
    {
93
        return $this->options;
94
    }
95
96
    /**
97
     * Reset data set values for all data points back to the defaults as in the
98
     * column definition
99
     *
100
     * @return $this For method chaining
101
     */
102
    public function clear()
103
    {
104
        $this->currentDataSet = array();
105
        $this->currentDataSet = array_fill_keys(
106
            $this->dataPoints,
107
            $this->dataPointMeta
108
        );
109
110
        return $this;
111
    }
112
113
    /**
114
     * Remove reference to all existing data points
115
     *
116
     * @return $this For method chaining
117
     */
118
    public function clearDataPoints()
119
    {
120
        $this->dataPoints = array();
121
122
        return $this;
123
    }
124
125
  /**
126
   * Increment the value for a key that makes up part of the currently focused
127
   * data object.
128
   *
129
   * @param string $key   The index to use
130
   * @param int    $value The value to increment by
131
   * @return $this
132
   * @throws \Exception if there is no data point, column or invalid type
133
   */
134
    public function increment($key, $value = 1)
135
    {
136
        if (!$this->currentDataPoint) {
137
            throw new \Exception('No data point in focus');
138
        }
139
140 View Code Duplication
        if (!isset($this->currentDataSet[$this->currentDataPoint][$key])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
141
            throw new \Exception($key . ' has not been defined');
142
        }
143
144
        if ($this->currentDataSet[$this->currentDataPoint][$key]['type'] !== 'integer') {
145
            throw new \Exception($key . ' is not a numeric column');
146
        }
147
148
        if (!is_int($value)) {
149
            throw new \Exception('Can only increment using a numeric value');
150
        }
151
152
        $this->currentDataSet[$this->currentDataPoint][$key]['value'] += $value;
153
154
        return $this;
155
    }
156
157
  /**
158
   * Directly set the value for a key that makes up part of the currently focused
159
   * data object.
160
   *
161
   * @param string         $key   The index to use
162
   * @param string|integer $value The value to set
163
   * @return $this
164
   * @throws \Exception
165
   */
166
    public function set($key, $value)
167
    {
168
        if (!$this->currentDataPoint) {
169
            throw new \Exception('No data point in focus');
170
        }
171
172 View Code Duplication
        if (!isset($this->currentDataSet[$this->currentDataPoint][$key])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
            throw new \Exception($key . ' has not been defined');
174
        }
175
        $this->currentDataSet[$this->currentDataPoint][$key]['value'] = $value;
176
177
        return $this;
178
    }
179
180
  /**
181
   * Set a focus for the current data object for which data can be manipulated.
182
   * If the key doesn't exist, it will be created using default column values.
183
   *
184
   * @param string $key The reference key to be used
185
   * @return $this
186
   */
187
    public function setPoint($key)
188
    {
189
        if (!isset($this->currentDataSet[$key])) {
190
            $this->addPoint($key);
191
        }
192
        $this->currentDataPoint = $key;
193
194
        return $this;
195
    }
196
197
  /**
198
   * Add a data point which will be shown on the report. This function should be
199
   * used prior to any kind of data manipulation as it will not setup a data
200
   * structure for manipulation.
201
   *
202
   * @param string $key The index to use
203
   * @return $this
204
   */
205
    public function addPoint($key)
206
    {
207
        if (!in_array($key, $this->dataPoints)) {
208
            $this->dataPoints[] = $key;
209
            $this->currentDataSet[$key] = $this->dataPointMeta;
210
        }
211
212
        return $this;
213
    }
214
215
  /**
216
   * Define a type of data that will be presented on the report or metadata that
217
   * will be used for calculations. In the latter case, within the options array
218
   * set "visible" to false.
219
   * At a minimum, the key needs to be set. In this case, the type will be string
220
   * and the key converted in to a title
221
   * .
222
   *
223
   * @param string $key          A reference key for the piece of data
224
   * @param string|integer $defaultValue The default also defines type of column
225
   * @param array  $options      Additional parameters for the column to use
226
   *
227
   * @return $this
228
   */
229
    public function column(
230
        $key,
231
        $defaultValue = '',
232
        $options = array()
233
    ) {
234
235
        $options['value'] = $defaultValue;
236
237
        // Auto guessing the type?
238
        if (!isset($options['type'])) {
239
            $options['type'] = gettype($defaultValue);
240
        }
241
        // Check whether hidden
242
        if (!isset($options['visible'])) {
243
            $options['visible'] = true;
244
        }
245
246
        // Does it have a title
247
        if (!isset($options['title']) && $options['visible'] === true) {
248
            $options['title'] = ucwords(str_replace('_', ' ', $key));
249
        }
250
251
        $this->dataPointMeta[$key] = $options;
252
253
        if ($options['visible'] == true) {
254
            $this->columnCount++;
255
        }
256
257
        return $this;
258
    }
259
260
    /**
261
   * Manually set the data which will be used for the current set. when
262
   * using this function, it will expect an associative array of arrays where
263
   * each entry has a further array of values which have a key matching that of
264
   * the meta data.
265
   * TODO - This is quite messy, rewrite more efficiently.
266
   *
267
   * @param array $inputData A set of data which conforms to the column specification
268
   * @return $this
269
   */
270
    public function setData($inputData)
271
    {
272
        // Combine raw data with the meta data
273
        foreach ($inputData as $key => $values) {
274
            $data = [];
275
            foreach ($this->dataPointMeta as $fieldKey => $field) {
276
                $data[$fieldKey] = array_merge($field, ['value' => $values[$fieldKey]]);
277
            }
278
            $this->currentDataSet[$key] = $data;
279
        }
280
281
        return $this;
282
    }
283
284
    /**
285
     * Return the information array relating to a specific column
286
     *
287
     * @param string|integer $key
288
     * @return array
289
     * @throws \Exception
290
     */
291
    public function columnInfo($key)
292
    {
293
        if (isset($this->dataPointMeta[$key])) {
294
            return $this->dataPointMeta[$key];
295
        } else {
296
            throw new \Exception($key . ' column has not been defined');
297
        }
298
    }
299
300
    /**
301
     * Retrieve the complete meta information relating to a data point
302
     *
303
     * @return array
304
     * @throws \Exception if the current data set is pointer-less
305
     */
306
    public function getPoint()
307
    {
308
        if (isset($this->currentDataSet[$this->currentDataPoint])) {
309
            return $this->currentDataSet[$this->currentDataPoint];
310
        } else {
311
            throw new \Exception('No data point to retrieve');
312
        }
313
    }
314
315
    /**
316
     * Return a specific piece of data from the current data point
317
     *
318
     * @param string|integer $key
319
     * @return mixed
320
     */
321
    public function getPointValue($key)
322
    {
323
        $point = $this->getPoint();
324
325
        return $point[$key]['value'];
326
    }
327
328
    /**
329
     * Return the number of data columns that have been defined
330
     *
331
     * @return integer
332
     */
333
    public function columnCount()
334
    {
335
        return count($this->dataPointMeta);
336
    }
337
338
    /**
339
     * Return the number of data points that have been defined
340
     *
341
     * @return integer
342
     */
343
    public function dataCount()
344
    {
345
        return count($this->currentDataSet);
346
    }
347
348
    /**
349
     * Return all the column information
350
     *
351
     * @return array
352
     */
353
    public function getIndex()
354
    {
355
        return $this->dataPointMeta;
356
    }
357
358
    /**
359
     * Return all the data from the current set
360
     *
361
     * @return array
362
     */
363
    public function getDataSet()
364
    {
365
        return $this->currentDataSet;
366
    }
367
368
    /**
369
     * Return the key for the current data point in focus
370
     *
371
     * @return string
372
     */
373
    public function getPointKey()
374
    {
375
        return $this->currentDataPoint;
376
    }
377
}
378