File size: 5,875 Bytes
d2897cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
<?php

namespace Mautic\CoreBundle\Helper\Chart;

use Mautic\CoreBundle\Helper\ColorHelper;

abstract class AbstractChart
{
    use DateRangeUnitTrait;

    /**
     * Datasets of the chart.
     *
     * @var array
     */
    protected $datasets = [];

    /**
     * Labels of the time axe.
     *
     * @var array
     */
    protected $labels = [];

    /**
     * Date from.
     *
     * @var \DateTimeInterface|\DateTime
     */
    protected $dateFrom;

    /**
     * Date to.
     *
     * @var \DateTimeInterface|\DateTime
     */
    protected $dateTo;

    /**
     * Timezone data is requested to be in.
     *
     * @var \DateTimeZone
     */
    protected $timezone;

    /**
     * Time unit.
     *
     * @var string
     */
    protected $unit;

    /**
     * True if unit is H, i, or s.
     *
     * @var bool
     */
    protected $isTimeUnit = false;

    /**
     * amount of items.
     *
     * @var int
     */
    protected $amount;

    /**
     * Default Mautic colors.
     *
     * @var array
     */
    public $colors = ['#4E5D9D', '#00B49C', '#FD9572', '#FDB933', '#757575', '#9C4E5C', '#694535', '#596935'];

    /**
     * Get chart time unit.
     *
     * @return string
     */
    public function getUnit()
    {
        return $this->unit;
    }

    /**
     * Create a DateInterval time unit.
     *
     * @param string $unit
     *
     * @return \DateInterval
     */
    public function getUnitInterval($unit = null)
    {
        if (!$unit) {
            $unit = $this->unit;
        }

        $isTime = in_array($unit, ['H', 'i', 's']) ? 'T' : '';

        if ('i' == $unit) {
            $unit = 'M';
        }

        return new \DateInterval('P'.$isTime.'1'.strtoupper($unit));
    }

    /**
     * Helper function to shorten/truncate a string.
     *
     * @param string $string
     * @param int    $length
     * @param string $append
     *
     * @return string
     */
    public static function truncate($string, $length = 100, $append = '...')
    {
        $string = trim($string);

        if (strlen($string) > $length) {
            $string = wordwrap($string, $length);
            $string = explode("\n", $string, 2);
            $string = $string[0].$append;
        }

        return $string;
    }

    /**
     * Sets the clones of the date range and validates it.
     */
    public function setDateRange(\DateTimeInterface $dateFrom, \DateTimeInterface $dateTo): void
    {
        $this->timezone = $dateFrom->getTimezone();
        /** @var \DateTime $dateFrom */
        $this->dateFrom = clone $dateFrom;
        /** @var \DateTime $dateTo */
        $this->dateTo   = clone $dateTo;

        // a diff of two identical dates returns 0, but we expect 24 hours
        if ($dateFrom == $dateTo) {
            $this->dateTo->modify('+1 day');
        }

        // If today, adjust dateTo to be end of today if unit is not time based or to the current hour if it is
        if (!$this->isTimeUnit) {
            $this->dateTo->setTime(23, 59, 59);

            return;
        }

        // If time aware and the to date is today, set the stats to the current hour to avoid empty future hours in graphs
        $now = new \DateTime();
        if ($now->format('Y-m-d') === $this->dateTo->format('Y-m-d')) {
            $this->dateTo = $now;
        }
    }

    /**
     * Modify the date to add one current time unit to it and subtract 1 second.
     * Can be used to get the current day results.
     */
    public function addOneUnitMinusOneSec(\DateTime &$date): void
    {
        $date->add($this->getUnitInterval())->modify('-1 sec');
    }

    /**
     * Count amount of time slots of a time unit from a date range.
     *
     * @return int
     */
    public function countAmountFromDateRange()
    {
        switch ($this->unit) {
            case 's':
                $amount = $this->dateTo->diff($this->dateFrom)->format('%s');
                ++$amount;
                break;
            case 'i':
                $amount = $this->dateTo->diff($this->dateFrom)->format('%i');
                ++$amount;
                break;
            case 'd':
                $amount = ($this->dateTo->diff($this->dateFrom)->format('%a') + 1);
                break;
            case 'W':
                $dayAmount = $this->dateTo->diff($this->dateFrom)->format('%a');
                $amount    = (ceil($dayAmount / 7) + 1);
                break;
            case 'm':
                $amount = $this->dateTo->diff($this->dateFrom)->format('%y') * 12 + $this->dateTo->diff($this->dateFrom)->format('%m');

                // Add 1 month if there are some days left
                if ($this->dateTo->diff($this->dateFrom)->format('%d') > 0) {
                    ++$amount;
                }

                // Add 1 month if count of days are greater or equal than in date to
                if ($this->dateFrom->format('d') >= $this->dateTo->format('d')) {
                    ++$amount;
                }
                break;
            case 'H':
                $dateDiff = $this->dateTo->diff($this->dateFrom);
                $amount   = $dateDiff->h + $dateDiff->days * 24;
                ++$amount;
                break;
            default:
                $amount = ($this->dateTo->diff($this->dateFrom)->format('%'.$this->unit) + 1);
                break;
        }

        return $amount;
    }

    /**
     * Generate unique color for the dataset.
     *
     * @param int $datasetId
     *
     * @return ColorHelper
     */
    public function configureColorHelper($datasetId)
    {
        $colorHelper = new ColorHelper();

        if (isset($this->colors[$datasetId])) {
            $color = $colorHelper->setHex($this->colors[$datasetId]);
        } else {
            $color = $colorHelper->buildRandomColor();
        }

        return $color;
    }
}