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
|
<?php
/**
* Piwik - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Period;
use Exception;
use Piwik\Container\StaticContainer;
use Piwik\Date;
use Piwik\Period;
use Piwik\Piwik;
use Piwik\Plugin;
/**
* Creates Period instances using the values used for the 'period' and 'date'
* query parameters.
*
* ## Custom Periods
*
* Plugins can define their own period factories all plugins to define new period types, in addition
* to "day", "week", "month", "year" and "range".
*
* To define a new period type:
*
* 1. create a new period class that derives from {@see \Piwik\Period}.
* 2. extend this class in a new PeriodFactory class and put it in /path/to/piwik/plugins/MyPlugin/PeriodFactory.php
*
* Period name collisions:
*
* If two plugins try to handle the same period label, the first one encountered will
* be used. In other words, avoid using another plugin's period label.
*/
abstract class Factory
{
public function __construct()
{
// empty
}
/**
* Returns true if this factory should handle the period/date string combination.
*
* @return bool
*/
public abstract function shouldHandle($strPeriod, $strDate);
/**
* Creates a period using the value of the 'date' query parameter.
*
* @param string $strPeriod
* @param string|Date $date
* @param string $timezone
* @return Period
*/
public abstract function make($strPeriod, $date, $timezone);
/**
* Creates a new Period instance with a period ID and {@link Date} instance.
*
* _Note: This method cannot create {@link Period\Range} periods._
*
* @param string $period `"day"`, `"week"`, `"month"`, `"year"`, `"range"`.
* @param Date|string $date A date within the period or the range of dates.
* @param Date|string $timezone Optional timezone that will be used only when $period is 'range' or $date is 'last|previous'
* @throws Exception If `$strPeriod` is invalid or $date is invalid.
* @return \Piwik\Period
*/
public static function build($period, $date, $timezone = 'UTC')
{
self::checkPeriodIsEnabled($period);
if (is_string($date)) {
list($period, $date) = self::convertRangeToDateIfNeeded($period, $date);
if (Period::isMultiplePeriod($date, $period)
|| $period == 'range'
) {
return new Range($period, $date, $timezone);
}
$dateObject = Date::factory($date);
} else if ($date instanceof Date) {
$dateObject = $date;
} else {
throw new \Exception("Invalid date supplied to Period\Factory::build(): " . gettype($date));
}
switch ($period) {
case 'day':
return new Day($dateObject);
case 'week':
return new Week($dateObject);
case 'month':
return new Month($dateObject);
case 'year':
return new Year($dateObject);
}
/** @var string[] $customPeriodFactories */
$customPeriodFactories = Plugin\Manager::getInstance()->findComponents('PeriodFactory', self::class);
foreach ($customPeriodFactories as $customPeriodFactoryClass) {
$customPeriodFactory = StaticContainer::get($customPeriodFactoryClass);
if ($customPeriodFactory->shouldHandle($period, $date)) {
return $customPeriodFactory->make($period, $date, $timezone);
}
}
throw new \Exception("Don't know how to create a '$period' period!");
}
public static function checkPeriodIsEnabled($period)
{
if (!self::isPeriodEnabledForAPI($period)) {
self::throwExceptionInvalidPeriod($period);
}
}
/**
* @param $strPeriod
* @throws \Exception
*/
private static function throwExceptionInvalidPeriod($strPeriod)
{
$periods = self::getPeriodsEnabledForAPI();
$periods = implode(", ", $periods);
$message = Piwik::translate('General_ExceptionInvalidPeriod', array($strPeriod, $periods));
throw new Exception($message);
}
private static function convertRangeToDateIfNeeded($period, $date)
{
if (is_string($period) && is_string($date) && $period === 'range') {
$dates = explode(',', $date);
if (count($dates) === 2 && $dates[0] === $dates[1]) {
$period = 'day';
$date = $dates[0];
}
}
return array($period, $date);
}
/**
* Creates a Period instance using a period, date and timezone.
*
* @param string $timezone The timezone of the date. Only used if `$date` is `'now'`, `'today'`,
* `'yesterday'` or `'yesterdaySameTime'`.
* @param string $period The period string: `"day"`, `"week"`, `"month"`, `"year"`, `"range"`.
* @param string $date The date or date range string. Can be a special value including
* `'now'`, `'today'`, `'yesterday'`, `'yesterdaySameTime'`.
* @return \Piwik\Period
*/
public static function makePeriodFromQueryParams($timezone, $period, $date)
{
if (empty($timezone)) {
$timezone = 'UTC';
}
list($period, $date) = self::convertRangeToDateIfNeeded($period, $date);
if ($period == 'range') {
self::checkPeriodIsEnabled('range');
$oPeriod = new Range('range', $date, $timezone, Date::factory('today', $timezone));
} else {
if (!($date instanceof Date)) {
if ($date == 'now' || $date == 'today') {
$date = date('Y-m-d', Date::factory('now', $timezone)->getTimestamp());
} elseif ($date == 'yesterday' || $date == 'yesterdaySameTime') {
$date = date('Y-m-d', Date::factory('now', $timezone)->subDay(1)->getTimestamp());
}
$date = Date::factory($date);
}
$oPeriod = Factory::build($period, $date);
}
return $oPeriod;
}
/**
* @param $period
* @return bool
*/
public static function isPeriodEnabledForAPI($period)
{
$periodValidator = new PeriodValidator();
return $periodValidator->isPeriodAllowedForAPI($period);
}
/**
* @return array
*/
public static function getPeriodsEnabledForAPI()
{
$periodValidator = new PeriodValidator();
return $periodValidator->getPeriodsAllowedForAPI();
}
}
|