PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.3.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.3.0
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 5 years ago Access 5 years ago Application 5 years ago Archive 5 years ago ArchiveProcessor 5 years ago Archiver 5 years ago AssetManager 5 years ago Auth 5 years ago Category 5 years ago CliMulti 5 years ago Columns 5 years ago Composer 5 years ago Concurrency 5 years ago Config 5 years ago Container 5 years ago CronArchive 5 years ago DataAccess 5 years ago DataFiles 5 years ago DataTable 5 years ago Db 5 years ago DeviceDetector 5 years ago Email 5 years ago Exception 5 years ago Http 5 years ago Intl 5 years ago Mail 5 years ago Measurable 5 years ago Menu 5 years ago Metrics 5 years ago Notification 5 years ago Period 5 years ago Plugin 5 years ago ProfessionalServices 5 years ago Report 5 years ago ReportRenderer 5 years ago Scheduler 5 years ago Segment 5 years ago Session 5 years ago Settings 5 years ago Tracker 5 years ago Translation 5 years ago UpdateCheck 5 years ago Updater 5 years ago Updates 5 years ago Validators 5 years ago View 5 years ago ViewDataTable 5 years ago Visualization 5 years ago Widget 5 years ago .htaccess 6 years ago Access.php 5 years ago Archive.php 5 years ago ArchiveProcessor.php 5 years ago AssetManager.php 5 years ago Auth.php 5 years ago AuthResult.php 5 years ago BaseFactory.php 5 years ago Cache.php 5 years ago CacheId.php 5 years ago CliMulti.php 5 years ago Common.php 5 years ago Config.php 5 years ago Console.php 5 years ago Context.php 5 years ago Cookie.php 5 years ago CronArchive.php 5 years ago DataArray.php 5 years ago DataTable.php 5 years ago Date.php 5 years ago Db.php 5 years ago DbHelper.php 5 years ago Development.php 5 years ago ErrorHandler.php 5 years ago EventDispatcher.php 5 years ago ExceptionHandler.php 5 years ago FileIntegrity.php 5 years ago Filechecks.php 5 years ago Filesystem.php 5 years ago FrontController.php 5 years ago Http.php 5 years ago IP.php 5 years ago Log.php 5 years ago LogDeleter.php 5 years ago Mail.php 5 years ago Metrics.php 5 years ago NoAccessException.php 5 years ago Nonce.php 5 years ago Notification.php 5 years ago NumberFormatter.php 5 years ago Option.php 5 years ago Period.php 5 years ago Piwik.php 5 years ago Plugin.php 5 years ago Profiler.php 5 years ago ProxyHeaders.php 5 years ago ProxyHttp.php 5 years ago QuickForm2.php 5 years ago RankingQuery.php 5 years ago ReportRenderer.php 5 years ago Segment.php 5 years ago Sequence.php 5 years ago Session.php 5 years ago SettingsPiwik.php 5 years ago SettingsServer.php 5 years ago Singleton.php 5 years ago Site.php 5 years ago SupportedBrowser.php 5 years ago TCPDF.php 5 years ago Theme.php 5 years ago Timer.php 5 years ago Tracker.php 5 years ago Twig.php 5 years ago Unzip.php 5 years ago UpdateCheck.php 5 years ago Updater.php 5 years ago UpdaterErrorException.php 5 years ago Updates.php 5 years ago Url.php 5 years ago UrlHelper.php 5 years ago Version.php 5 years ago View.php 5 years ago bootstrap.php 5 years ago dispatch.php 5 years ago testMinimumPhpVersion.php 5 years ago
Period.php
492 lines
1 <?php
2 /**
3 * Matomo - 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 * Returns whether the given period date range intersects with this one.
267 *
268 * @param Period $other
269 * @return bool
270 */
271 public function isPeriodIntersectingWith(Period $other)
272 {
273 return !($this->getDateEnd()->getTimestamp() < $other->getDateStart()->getTimestamp()
274 || $this->getDateStart()->getTimestamp() > $other->getDateEnd()->getTimestamp());
275 }
276
277 /**
278 * Returns the start day and day after the end day for this period in the given timezone.
279 *
280 * @param Date[] $timezone
281 */
282 public function getBoundsInTimezone(string $timezone)
283 {
284 $date1 = $this->getDateTimeStart()->setTimezone($timezone);
285 $date2 = $this->getDateTimeEnd()->setTimezone($timezone);
286
287 return [$date1, $date2];
288 }
289
290 /**
291 * Add a date to the period.
292 *
293 * Protected because adding periods after initialization is not supported.
294 *
295 * @param \Piwik\Period $period Valid Period object
296 * @ignore
297 */
298 protected function addSubperiod($period)
299 {
300 $this->subperiods[] = $period;
301 }
302
303 /**
304 * Returns a list of strings representing the current period.
305 *
306 * @param string $format The format of each individual day.
307 * @return array|string An array of string dates that this period consists of.
308 */
309 public function toString($format = "Y-m-d")
310 {
311 $this->generate();
312
313 $dateString = array();
314 foreach ($this->subperiods as $period) {
315 $childPeriodStr = $period->toString($format);
316 if (is_array($childPeriodStr)) {
317 $childPeriodStr = implode(",", $childPeriodStr);
318 }
319
320 $dateString[] = $childPeriodStr;
321 }
322
323 return $dateString;
324 }
325
326 /**
327 * See {@link toString()}.
328 *
329 * @return string
330 */
331 public function __toString()
332 {
333 return implode(",", $this->toString());
334 }
335
336 /**
337 * Returns a pretty string describing this period.
338 *
339 * @return string
340 */
341 abstract public function getPrettyString();
342
343 /**
344 * Returns a short string description of this period that is localized with the currently used
345 * language.
346 *
347 * @return string
348 */
349 abstract public function getLocalizedShortString();
350
351 /**
352 * Returns a long string description of this period that is localized with the currently used
353 * language.
354 *
355 * @return string
356 */
357 abstract public function getLocalizedLongString();
358
359 /**
360 * Returns the label of the period type that is one size smaller than this one, or null if
361 * it's the smallest.
362 *
363 * Range periods and other such 'period collections' are not considered as separate from
364 * the value type of the collection. So a range period will return the result of the
365 * subperiod's `getImmediateChildPeriodLabel()` method.
366 *
367 * @ignore
368 * @return string|null
369 */
370 abstract public function getImmediateChildPeriodLabel();
371
372 /**
373 * Returns the label of the period type that is one size bigger than this one, or null
374 * if it's the biggest.
375 *
376 * Range periods and other such 'period collections' are not considered as separate from
377 * the value type of the collection. So a range period will return the result of the
378 * subperiod's `getParentPeriodLabel()` method.
379 *
380 * @ignore
381 */
382 abstract public function getParentPeriodLabel();
383
384 /**
385 * Returns the date range string comprising two dates
386 *
387 * @return string eg, `'2012-01-01,2012-01-31'`.
388 */
389 public function getRangeString()
390 {
391 $dateStart = $this->getDateStart();
392 $dateEnd = $this->getDateEnd();
393
394 return $dateStart->toString("Y-m-d") . "," . $dateEnd->toString("Y-m-d");
395 }
396
397 /**
398 * @param string $format
399 *
400 * @return mixed
401 */
402 protected function getTranslatedRange($format)
403 {
404 $dateStart = $this->getDateStart();
405 $dateEnd = $this->getDateEnd();
406 list($formatStart, $formatEnd) = $this->explodeFormat($format);
407
408 $string = $dateStart->getLocalized($formatStart);
409 $string .= $dateEnd->getLocalized($formatEnd, false);
410
411 return $string;
412 }
413
414 /**
415 * Explodes the given format into two pieces. One that can be user for start date and the other for end date
416 *
417 * @param $format
418 * @return array
419 */
420 protected function explodeFormat($format)
421 {
422 $intervalTokens = array(
423 array('d', 'E', 'C'),
424 array('M', 'L'),
425 array('y')
426 );
427
428 $offset = strlen($format);
429 // replace string literals encapsulated by ' with same country of *
430 $cleanedFormat = preg_replace_callback('/(\'[^\']+\')/', array($this, 'replaceWithStars'), $format);
431
432 // search for first duplicate date field
433 foreach ($intervalTokens AS $tokens) {
434 if (preg_match_all('/[' . implode('|', $tokens) . ']+/', $cleanedFormat, $matches, PREG_OFFSET_CAPTURE) &&
435 count($matches[0]) > 1 && $offset > $matches[0][1][1]
436 ) {
437 $offset = $matches[0][1][1];
438 }
439 }
440
441 return array(substr($format, 0, $offset), substr($format, $offset));
442 }
443
444 private function replaceWithStars($matches)
445 {
446 return str_repeat("*", strlen($matches[0]));
447 }
448
449 protected function getRangeFormat($short = false)
450 {
451 $maxDifference = 'D';
452 if ($this->getDateStart()->toString('y') != $this->getDateEnd()->toString('y')) {
453 $maxDifference = 'Y';
454 } elseif ($this->getDateStart()->toString('m') != $this->getDateEnd()->toString('m')) {
455 $maxDifference = 'M';
456 }
457
458 $dateTimeFormatProvider = StaticContainer::get('Piwik\Intl\Data\Provider\DateTimeFormatProvider');
459
460 return $dateTimeFormatProvider->getRangeFormatPattern($short, $maxDifference);
461 }
462
463 /**
464 * Returns all child periods that exist within this periods entire date range. Cascades
465 * downwards over all period types that are smaller than this one. For example, month periods
466 * will cascade to week and day periods and year periods will cascade to month, week and day
467 * periods.
468 *
469 * The method will not return periods that are outside the range of this period.
470 *
471 * @return Period[]
472 * @ignore
473 */
474 public function getAllOverlappingChildPeriods()
475 {
476 return $this->getAllOverlappingChildPeriodsInRange($this->getDateStart(), $this->getDateEnd());
477 }
478
479 private function getAllOverlappingChildPeriodsInRange(Date $dateStart, Date $dateEnd)
480 {
481 $result = array();
482
483 $childPeriodType = $this->getImmediateChildPeriodLabel();
484 if (empty($childPeriodType)) {
485 return $result;
486 }
487
488 $childPeriods = Factory::build($childPeriodType, $dateStart->toString() . ',' . $dateEnd->toString());
489 return array_merge($childPeriods->getSubperiods(), $childPeriods->getAllOverlappingChildPeriodsInRange($dateStart, $dateEnd));
490 }
491 }
492