update Piwik to version 2.16 (fixes #91)

This commit is contained in:
oliver 2016-04-10 18:55:57 +02:00
commit d885a4baa9
5833 changed files with 418860 additions and 226988 deletions

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -8,41 +8,31 @@
*/
namespace Piwik;
use Exception;
use Piwik\Period\Day;
use Piwik\Period\Month;
use Piwik\Container\StaticContainer;
use Piwik\Period\Factory;
use Piwik\Period\Range;
use Piwik\Period\Week;
use Piwik\Period\Year;
use Piwik\Translation\Translator;
/**
* Date range representation.
*
*
* Piwik allows users to view aggregated statistics for single days and for date
* ranges consisting of several days. When requesting data, a **date** string and
* a **period** string must be used to specify the date range that the data regards.
* This is the class Piwik uses to represent and manipulate those date ranges.
*
*
* There are five types of periods in Piwik: day, week, month, year and range,
* where **range** is any date range. The reason the other periods exist instead
* of just **range** is that Piwik will pre-archive reports for days, weeks, months
* and years, while every other date range is archived on-demand.
*
* ### Examples
*
* **Building a period from 'date' and 'period' query parameters**
*
* $date = Common::getRequestVar('date', null, 'string');
* $period = Common::getRequestVar('period', null, 'string');
* $periodObject = Period::advancedFactory($period, $date);
*
* and years, while every custom date range is archived on-demand.
*
* @api
*/
abstract class Period
{
/**
* Array of subperiods
* @var \Piwik\Period[]
* @var Period[]
*/
protected $subperiods = array();
protected $subperiodsProcessed = false;
@ -57,77 +47,39 @@ abstract class Period
*/
protected $date = null;
/**
* @var Translator
*/
protected $translator;
/**
* Constructor.
*
*
* @param Date $date
* @ignore
*/
public function __construct(Date $date)
{
$this->date = clone $date;
}
/**
* Creates a new Period instance with a period ID and {@link Date} instance.
*
* _Note: This method cannot create {@link Period\Range} periods._
*
* @param string $strPeriod `"day"`, `"week"`, `"month"`, `"year"`, `"range"`.
* @param Date|string $date A date within the period or the range of dates.
* @throws Exception If `$strPeriod` is invalid.
* @return \Piwik\Period
*/
static public function factory($strPeriod, $date)
{
if (is_string($date)) {
if (Period::isMultiplePeriod($date, $strPeriod) || $strPeriod == 'range') {
return new Range($strPeriod, $date);
}
$date = Date::factory($date);
}
switch ($strPeriod) {
case 'day':
return new Day($date);
break;
case 'week':
return new Week($date);
break;
case 'month':
return new Month($date);
break;
case 'year':
return new Year($date);
break;
default:
$message = Piwik::translate(
'General_ExceptionInvalidPeriod', array($strPeriod, 'day, week, month, year, range'));
throw new Exception($message);
break;
}
$this->translator = StaticContainer::get('Piwik\Translation\Translator');
}
/**
* Returns true if `$dateString` and `$period` represent multiple periods.
*
*
* Will return true for date/period combinations where date references multiple
* dates and period is not `'range'`. For example, will return true for:
*
*
* - **date** = `2012-01-01,2012-02-01` and **period** = `'day'`
* - **date** = `2012-01-01,2012-02-01` and **period** = `'week'`
* - **date** = `last7` and **period** = `'month'`
*
*
* etc.
*
*
* @static
* @param $dateString The **date** query parameter value.
* @param $period The **period** query parameter value.
* @param $dateString string The **date** query parameter value.
* @param $period string The **period** query parameter value.
* @return boolean
*/
public static function isMultiplePeriod($dateString, $period)
@ -139,35 +91,22 @@ abstract class Period
}
/**
* Creates a Period instance using a period, date and timezone.
* Checks the given date format whether it is a correct date format and if not, throw an exception.
*
* @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
* For valid date formats have a look at the {@link \Piwik\Date::factory()} method and
* {@link isMultiplePeriod()} method.
*
* @param string $dateString
* @throws \Exception If `$dateString` is in an invalid format or if the time is before
* Tue, 06 Aug 1991.
*/
public static function makePeriodFromQueryParams($timezone, $period, $date)
public static function checkDateFormat($dateString)
{
if (empty($timezone)) {
$timezone = 'UTC';
if (self::isMultiplePeriod($dateString, 'day')) {
return;
}
if ($period == 'range') {
$oPeriod = new Period\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 = Period::factory($period, $date);
}
return $oPeriod;
Date::factory($dateString);
}
/**
@ -178,16 +117,20 @@ abstract class Period
public function getDateStart()
{
$this->generate();
if (count($this->subperiods) == 0) {
return $this->getDate();
}
$periods = $this->getSubperiods();
/** @var $currentPeriod Period */
$currentPeriod = $periods[0];
while ($currentPeriod->getNumberOfSubperiods() > 0) {
$periods = $currentPeriod->getSubperiods();
$periods = $currentPeriod->getSubperiods();
$currentPeriod = $periods[0];
}
return $currentPeriod->getDate();
}
@ -199,22 +142,26 @@ abstract class Period
public function getDateEnd()
{
$this->generate();
if (count($this->subperiods) == 0) {
return $this->getDate();
}
$periods = $this->getSubperiods();
/** @var $currentPeriod Period */
$currentPeriod = $periods[count($periods) - 1];
while ($currentPeriod->getNumberOfSubperiods() > 0) {
$periods = $currentPeriod->getSubperiods();
$periods = $currentPeriod->getSubperiods();
$currentPeriod = $periods[count($periods) - 1];
}
return $currentPeriod->getDate();
}
/**
* Returns the period ID.
*
*
* @return int A unique integer for this type of period.
*/
public function getId()
@ -224,7 +171,7 @@ abstract class Period
/**
* Returns the label for the current period.
*
*
* @return string `"day"`, `"week"`, `"month"`, `"year"`, `"range"`
*/
public function getLabel()
@ -247,7 +194,7 @@ abstract class Period
/**
* Returns the number of available subperiods.
*
*
* @return int
*/
public function getNumberOfSubperiods()
@ -259,7 +206,7 @@ abstract class Period
/**
* Returns the set of Period instances that together make up this period. For a year,
* this would be 12 months. For a month this would be 28-31 days. Etc.
*
*
* @return Period[]
*/
public function getSubperiods()
@ -290,16 +237,18 @@ abstract class Period
public function toString($format = "Y-m-d")
{
$this->generate();
$dateString = array();
foreach ($this->subperiods as $period) {
$dateString[] = $period->toString($format);
}
return $dateString;
}
/**
* See {@link toString()}.
*
*
* @return string
*/
public function __toString()
@ -309,7 +258,7 @@ abstract class Period
/**
* Returns a pretty string describing this period.
*
*
* @return string
*/
abstract public function getPrettyString();
@ -317,7 +266,7 @@ abstract class Period
/**
* Returns a short string description of this period that is localized with the currently used
* language.
*
*
* @return string
*/
abstract public function getLocalizedShortString();
@ -325,18 +274,141 @@ abstract class Period
/**
* Returns a long string description of this period that is localized with the currently used
* language.
*
*
* @return string
*/
abstract public function getLocalizedLongString();
/**
* Returns a succinct string describing this period.
*
* Returns the label of the period type that is one size smaller than this one, or null if
* it's the smallest.
*
* Range periods and other such 'period collections' are not considered as separate from
* the value type of the collection. So a range period will return the result of the
* subperiod's `getImmediateChildPeriodLabel()` method.
*
* @ignore
* @return string|null
*/
abstract public function getImmediateChildPeriodLabel();
/**
* Returns the label of the period type that is one size bigger than this one, or null
* if it's the biggest.
*
* Range periods and other such 'period collections' are not considered as separate from
* the value type of the collection. So a range period will return the result of the
* subperiod's `getParentPeriodLabel()` method.
*
* @ignore
*/
abstract public function getParentPeriodLabel();
/**
* Returns the date range string comprising two dates
*
* @return string eg, `'2012-01-01,2012-01-31'`.
*/
public function getRangeString()
{
return $this->getDateStart()->toString("Y-m-d") . "," . $this->getDateEnd()->toString("Y-m-d");
$dateStart = $this->getDateStart();
$dateEnd = $this->getDateEnd();
return $dateStart->toString("Y-m-d") . "," . $dateEnd->toString("Y-m-d");
}
/**
* @param string $format
*
* @return mixed
*/
protected function getTranslatedRange($format)
{
$dateStart = $this->getDateStart();
$dateEnd = $this->getDateEnd();
list($formatStart, $formatEnd) = $this->explodeFormat($format);
$string = $dateStart->getLocalized($formatStart);
$string .= $dateEnd->getLocalized($formatEnd);
return $string;
}
/**
* Explodes the given format into two pieces. One that can be user for start date and the other for end date
*
* @param $format
* @return array
*/
protected function explodeFormat($format)
{
$intervalTokens = array(
array('d', 'E', 'C'),
array('M', 'L'),
array('y')
);
$offset = strlen($format);
// replace string literals encapsulated by ' with same country of *
$cleanedFormat = preg_replace_callback('/(\'[^\']+\')/', array($this, 'replaceWithStars'), $format);
// search for first duplicate date field
foreach ($intervalTokens AS $tokens) {
if (preg_match_all('/[' . implode('|', $tokens) . ']+/', $cleanedFormat, $matches, PREG_OFFSET_CAPTURE) &&
count($matches[0]) > 1 && $offset > $matches[0][1][1]
) {
$offset = $matches[0][1][1];
}
}
return array(substr($format, 0, $offset), substr($format, $offset));
}
private function replaceWithStars($matches)
{
return str_repeat("*", strlen($matches[0]));
}
protected function getRangeFormat($short = false)
{
$maxDifference = 'D';
if ($this->getDateStart()->toString('y') != $this->getDateEnd()->toString('y')) {
$maxDifference = 'Y';
} elseif ($this->getDateStart()->toString('m') != $this->getDateEnd()->toString('m')) {
$maxDifference = 'M';
}
$dateTimeFormatProvider = StaticContainer::get('Piwik\Intl\Data\Provider\DateTimeFormatProvider');
return $dateTimeFormatProvider->getRangeFormatPattern($short, $maxDifference);
}
/**
* Returns all child periods that exist within this periods entire date range. Cascades
* downwards over all period types that are smaller than this one. For example, month periods
* will cascade to week and day periods and year periods will cascade to month, week and day
* periods.
*
* The method will not return periods that are outside the range of this period.
*
* @return Period[]
* @ignore
*/
public function getAllOverlappingChildPeriods()
{
return $this->getAllOverlappingChildPeriodsInRange($this->getDateStart(), $this->getDateEnd());
}
private function getAllOverlappingChildPeriodsInRange(Date $dateStart, Date $dateEnd)
{
$result = array();
$childPeriodType = $this->getImmediateChildPeriodLabel();
if (empty($childPeriodType)) {
return $result;
}
$childPeriods = Factory::build($childPeriodType, $dateStart->toString() . ',' . $dateEnd->toString());
return array_merge($childPeriods->getSubperiods(), $childPeriods->getAllOverlappingChildPeriodsInRange($dateStart, $dateEnd));
}
}