PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.3.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.3.1
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Period.php
matomo / app / core Last commit date
API 6 years ago Access 6 years ago Application 6 years ago Archive 6 years ago ArchiveProcessor 6 years ago Archiver 6 years ago AssetManager 6 years ago Auth 6 years ago Category 6 years ago CliMulti 6 years ago Columns 6 years ago Composer 6 years ago Concurrency 6 years ago Config 6 years ago Container 6 years ago CronArchive 6 years ago DataAccess 5 years ago DataFiles 6 years ago DataTable 6 years ago Db 6 years ago DeviceDetector 5 years ago Email 6 years ago Exception 6 years ago Http 6 years ago Intl 6 years ago Mail 6 years ago Measurable 6 years ago Menu 6 years ago Metrics 6 years ago Notification 6 years ago Period 6 years ago Plugin 6 years ago ProfessionalServices 6 years ago Report 6 years ago ReportRenderer 6 years ago Scheduler 6 years ago Segment 6 years ago Session 6 years ago Settings 6 years ago Tracker 5 years ago Translation 6 years ago UpdateCheck 6 years ago Updater 6 years ago Updates 6 years ago Validators 6 years ago View 6 years ago ViewDataTable 6 years ago Visualization 6 years ago Widget 6 years ago .htaccess 6 years ago Access.php 6 years ago Archive.php 6 years ago ArchiveProcessor.php 6 years ago AssetManager.php 6 years ago Auth.php 6 years ago BaseFactory.php 6 years ago Cache.php 6 years ago CacheId.php 6 years ago CliMulti.php 6 years ago Common.php 6 years ago Config.php 6 years ago Console.php 6 years ago Context.php 6 years ago Cookie.php 5 years ago CronArchive.php 5 years ago DataArray.php 6 years ago DataTable.php 6 years ago Date.php 6 years ago Db.php 6 years ago DbHelper.php 6 years ago Development.php 6 years ago DeviceDetectorFactory.php 6 years ago ErrorHandler.php 6 years ago EventDispatcher.php 6 years ago ExceptionHandler.php 6 years ago FileIntegrity.php 6 years ago Filechecks.php 6 years ago Filesystem.php 6 years ago FrontController.php 6 years ago Http.php 6 years ago IP.php 6 years ago Log.php 6 years ago LogDeleter.php 6 years ago Mail.php 6 years ago Metrics.php 6 years ago MetricsFormatter.php 6 years ago Nonce.php 5 years ago Notification.php 6 years ago NumberFormatter.php 6 years ago Option.php 5 years ago Period.php 6 years ago Piwik.php 6 years ago Plugin.php 6 years ago Profiler.php 6 years ago ProxyHeaders.php 6 years ago ProxyHttp.php 6 years ago QuickForm2.php 6 years ago RankingQuery.php 6 years ago Registry.php 6 years ago ReportRenderer.php 6 years ago ScheduledTask.php 6 years ago Segment.php 6 years ago Sequence.php 6 years ago Session.php 6 years ago SettingsPiwik.php 6 years ago SettingsServer.php 6 years ago Singleton.php 6 years ago Site.php 6 years ago TCPDF.php 6 years ago TaskScheduler.php 6 years ago Theme.php 6 years ago Timer.php 6 years ago Tracker.php 6 years ago Translate.php 6 years ago Twig.php 6 years ago Unzip.php 6 years ago UpdateCheck.php 6 years ago Updater.php 6 years ago Updates.php 6 years ago Url.php 6 years ago UrlHelper.php 6 years ago Version.php 5 years ago View.php 6 years ago bootstrap.php 6 years ago dispatch.php 6 years ago testMinimumPhpVersion.php 6 years ago
Period.php
467 lines
1 <?php
2 /**
3 * Piwik - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9 namespace Piwik;
10
11 use Piwik\Container\StaticContainer;
12 use Piwik\Period\Factory;
13 use Piwik\Period\Range;
14 use Piwik\Translation\Translator;
15
16 /**
17 * Date range representation.
18 *
19 * Piwik allows users to view aggregated statistics for single days and for date
20 * ranges consisting of several days. When requesting data, a **date** string and
21 * a **period** string must be used to specify the date range that the data regards.
22 * This is the class Piwik uses to represent and manipulate those date ranges.
23 *
24 * There are five types of periods in Piwik: day, week, month, year and range,
25 * where **range** is any date range. The reason the other periods exist instead
26 * of just **range** is that Piwik will pre-archive reports for days, weeks, months
27 * and years, while every custom date range is archived on-demand.
28 *
29 * @api
30 */
31 abstract class Period
32 {
33 /**
34 * Array of subperiods
35 * @var Period[]
36 */
37 protected $subperiods = array();
38 protected $subperiodsProcessed = false;
39
40 /**
41 * @var string
42 */
43 protected $label = null;
44
45 /**
46 * @var Date
47 */
48 protected $date = null;
49
50 /**
51 * @var Translator
52 */
53 protected $translator;
54
55 /**
56 * Constructor.
57 *
58 * @param Date $date
59 * @ignore
60 */
61 public function __construct(Date $date)
62 {
63 $this->date = clone $date;
64
65 $this->translator = StaticContainer::get('Piwik\Translation\Translator');
66 }
67
68 public function __sleep()
69 {
70 return [
71 'date',
72 ];
73 }
74
75 public function __wakeup()
76 {
77 $this->translator = StaticContainer::get('Piwik\Translation\Translator');
78 }
79
80 /**
81 * Returns true if `$dateString` and `$period` represent multiple periods.
82 *
83 * Will return true for date/period combinations where date references multiple
84 * dates and period is not `'range'`. For example, will return true for:
85 *
86 * - **date** = `2012-01-01,2012-02-01` and **period** = `'day'`
87 * - **date** = `2012-01-01,2012-02-01` and **period** = `'week'`
88 * - **date** = `last7` and **period** = `'month'`
89 *
90 * etc.
91 *
92 * @static
93 * @param $dateString string The **date** query parameter value.
94 * @param $period string The **period** query parameter value.
95 * @return boolean
96 */
97 public static function isMultiplePeriod($dateString, $period)
98 {
99 return is_string($dateString)
100 && (preg_match('/^(last|previous){1}([0-9]*)$/D', $dateString, $regs)
101 || Range::parseDateRange($dateString))
102 && $period != 'range';
103 }
104
105 /**
106 * Checks the given date format whether it is a correct date format and if not, throw an exception.
107 *
108 * For valid date formats have a look at the {@link \Piwik\Date::factory()} method and
109 * {@link isMultiplePeriod()} method.
110 *
111 * @param string $dateString
112 * @throws \Exception If `$dateString` is in an invalid format or if the time is before
113 * Tue, 06 Aug 1991.
114 */
115 public static function checkDateFormat($dateString)
116 {
117 if (self::isMultiplePeriod($dateString, 'day')) {
118 return;
119 }
120
121 Date::factory($dateString);
122 }
123
124 /**
125 * Returns the first day of the period.
126 *
127 * @return Date
128 */
129 public function getDateStart()
130 {
131 $this->generate();
132
133 if (count($this->subperiods) == 0) {
134 return $this->getDate();
135 }
136
137 $periods = $this->getSubperiods();
138
139 /** @var $currentPeriod Period */
140 $currentPeriod = $periods[0];
141 while ($currentPeriod->getNumberOfSubperiods() > 0) {
142 $periods = $currentPeriod->getSubperiods();
143 $currentPeriod = $periods[0];
144 }
145
146 return $currentPeriod->getDate();
147 }
148
149 /**
150 * Returns the start date & time of this period.
151 *
152 * @return Date
153 */
154 public function getDateTimeStart()
155 {
156 return $this->getDateStart()->getStartOfDay();
157 }
158
159 /**
160 * Returns the end date & time of this period.
161 *
162 * @return Date
163 */
164 public function getDateTimeEnd()
165 {
166 return $this->getDateEnd()->getEndOfDay();
167 }
168
169 /**
170 * Returns the last day of the period.
171 *
172 * @return Date
173 */
174 public function getDateEnd()
175 {
176 $this->generate();
177
178 if (count($this->subperiods) == 0) {
179 return $this->getDate();
180 }
181
182 $periods = $this->getSubperiods();
183
184 /** @var $currentPeriod Period */
185 $currentPeriod = $periods[count($periods) - 1];
186 while ($currentPeriod->getNumberOfSubperiods() > 0) {
187 $periods = $currentPeriod->getSubperiods();
188 $currentPeriod = $periods[count($periods) - 1];
189 }
190
191 return $currentPeriod->getDate();
192 }
193
194 /**
195 * Returns the period ID.
196 *
197 * @return int A unique integer for this type of period.
198 */
199 public function getId()
200 {
201 return Piwik::$idPeriods[$this->getLabel()];
202 }
203
204 /**
205 * Returns the label for the current period.
206 *
207 * @return string `"day"`, `"week"`, `"month"`, `"year"`, `"range"`
208 */
209 public function getLabel()
210 {
211 return $this->label;
212 }
213
214 /**
215 * @return Date
216 */
217 protected function getDate()
218 {
219 return $this->date;
220 }
221
222 protected function generate()
223 {
224 $this->subperiodsProcessed = true;
225 }
226
227 /**
228 * Returns the number of available subperiods.
229 *
230 * @return int
231 */
232 public function getNumberOfSubperiods()
233 {
234 $this->generate();
235 return count($this->subperiods);
236 }
237
238 /**
239 * Returns the set of Period instances that together make up this period. For a year,
240 * this would be 12 months. For a month this would be 28-31 days. Etc.
241 *
242 * @return Period[]
243 */
244 public function getSubperiods()
245 {
246 $this->generate();
247 return $this->subperiods;
248 }
249
250 /**
251 * Returns whether the date `$date` is within the current period or not.
252 *
253 * Note: the time component of the period's dates and `$date` is ignored.
254 *
255 * @param Date $today
256 * @return bool
257 */
258 public function isDateInPeriod(Date $date)
259 {
260 $ts = $date->getStartOfDay()->getTimestamp();
261 return $ts >= $this->getDateStart()->getStartOfDay()->getTimestamp()
262 && $ts < $this->getDateEnd()->addDay(1)->getStartOfDay()->getTimestamp();
263 }
264
265 /**
266 * Add a date to the period.
267 *
268 * Protected because adding periods after initialization is not supported.
269 *
270 * @param \Piwik\Period $period Valid Period object
271 * @ignore
272 */
273 protected function addSubperiod($period)
274 {
275 $this->subperiods[] = $period;
276 }
277
278 /**
279 * Returns a list of strings representing the current period.
280 *
281 * @param string $format The format of each individual day.
282 * @return array|string An array of string dates that this period consists of.
283 */
284 public function toString($format = "Y-m-d")
285 {
286 $this->generate();
287
288 $dateString = array();
289 foreach ($this->subperiods as $period) {
290 $childPeriodStr = $period->toString($format);
291 if (is_array($childPeriodStr)) {
292 $childPeriodStr = implode(",", $childPeriodStr);
293 }
294
295 $dateString[] = $childPeriodStr;
296 }
297
298 return $dateString;
299 }
300
301 /**
302 * See {@link toString()}.
303 *
304 * @return string
305 */
306 public function __toString()
307 {
308 return implode(",", $this->toString());
309 }
310
311 /**
312 * Returns a pretty string describing this period.
313 *
314 * @return string
315 */
316 abstract public function getPrettyString();
317
318 /**
319 * Returns a short string description of this period that is localized with the currently used
320 * language.
321 *
322 * @return string
323 */
324 abstract public function getLocalizedShortString();
325
326 /**
327 * Returns a long string description of this period that is localized with the currently used
328 * language.
329 *
330 * @return string
331 */
332 abstract public function getLocalizedLongString();
333
334 /**
335 * Returns the label of the period type that is one size smaller than this one, or null if
336 * it's the smallest.
337 *
338 * Range periods and other such 'period collections' are not considered as separate from
339 * the value type of the collection. So a range period will return the result of the
340 * subperiod's `getImmediateChildPeriodLabel()` method.
341 *
342 * @ignore
343 * @return string|null
344 */
345 abstract public function getImmediateChildPeriodLabel();
346
347 /**
348 * Returns the label of the period type that is one size bigger than this one, or null
349 * if it's the biggest.
350 *
351 * Range periods and other such 'period collections' are not considered as separate from
352 * the value type of the collection. So a range period will return the result of the
353 * subperiod's `getParentPeriodLabel()` method.
354 *
355 * @ignore
356 */
357 abstract public function getParentPeriodLabel();
358
359 /**
360 * Returns the date range string comprising two dates
361 *
362 * @return string eg, `'2012-01-01,2012-01-31'`.
363 */
364 public function getRangeString()
365 {
366 $dateStart = $this->getDateStart();
367 $dateEnd = $this->getDateEnd();
368
369 return $dateStart->toString("Y-m-d") . "," . $dateEnd->toString("Y-m-d");
370 }
371
372 /**
373 * @param string $format
374 *
375 * @return mixed
376 */
377 protected function getTranslatedRange($format)
378 {
379 $dateStart = $this->getDateStart();
380 $dateEnd = $this->getDateEnd();
381 list($formatStart, $formatEnd) = $this->explodeFormat($format);
382
383 $string = $dateStart->getLocalized($formatStart);
384 $string .= $dateEnd->getLocalized($formatEnd, false);
385
386 return $string;
387 }
388
389 /**
390 * Explodes the given format into two pieces. One that can be user for start date and the other for end date
391 *
392 * @param $format
393 * @return array
394 */
395 protected function explodeFormat($format)
396 {
397 $intervalTokens = array(
398 array('d', 'E', 'C'),
399 array('M', 'L'),
400 array('y')
401 );
402
403 $offset = strlen($format);
404 // replace string literals encapsulated by ' with same country of *
405 $cleanedFormat = preg_replace_callback('/(\'[^\']+\')/', array($this, 'replaceWithStars'), $format);
406
407 // search for first duplicate date field
408 foreach ($intervalTokens AS $tokens) {
409 if (preg_match_all('/[' . implode('|', $tokens) . ']+/', $cleanedFormat, $matches, PREG_OFFSET_CAPTURE) &&
410 count($matches[0]) > 1 && $offset > $matches[0][1][1]
411 ) {
412 $offset = $matches[0][1][1];
413 }
414 }
415
416 return array(substr($format, 0, $offset), substr($format, $offset));
417 }
418
419 private function replaceWithStars($matches)
420 {
421 return str_repeat("*", strlen($matches[0]));
422 }
423
424 protected function getRangeFormat($short = false)
425 {
426 $maxDifference = 'D';
427 if ($this->getDateStart()->toString('y') != $this->getDateEnd()->toString('y')) {
428 $maxDifference = 'Y';
429 } elseif ($this->getDateStart()->toString('m') != $this->getDateEnd()->toString('m')) {
430 $maxDifference = 'M';
431 }
432
433 $dateTimeFormatProvider = StaticContainer::get('Piwik\Intl\Data\Provider\DateTimeFormatProvider');
434
435 return $dateTimeFormatProvider->getRangeFormatPattern($short, $maxDifference);
436 }
437
438 /**
439 * Returns all child periods that exist within this periods entire date range. Cascades
440 * downwards over all period types that are smaller than this one. For example, month periods
441 * will cascade to week and day periods and year periods will cascade to month, week and day
442 * periods.
443 *
444 * The method will not return periods that are outside the range of this period.
445 *
446 * @return Period[]
447 * @ignore
448 */
449 public function getAllOverlappingChildPeriods()
450 {
451 return $this->getAllOverlappingChildPeriodsInRange($this->getDateStart(), $this->getDateEnd());
452 }
453
454 private function getAllOverlappingChildPeriodsInRange(Date $dateStart, Date $dateEnd)
455 {
456 $result = array();
457
458 $childPeriodType = $this->getImmediateChildPeriodLabel();
459 if (empty($childPeriodType)) {
460 return $result;
461 }
462
463 $childPeriods = Factory::build($childPeriodType, $dateStart->toString() . ',' . $dateEnd->toString());
464 return array_merge($childPeriods->getSubperiods(), $childPeriods->getAllOverlappingChildPeriodsInRange($dateStart, $dateEnd));
465 }
466 }
467