public function getUrlParameterDateString($idSite, $period, $date, $segment)
 {
     $segmentCreatedTime = $this->getCreatedTimeOfSegment($idSite, $segment);
     $oldestDateToProcessForNewSegment = $this->getOldestDateToProcessForNewSegment($segmentCreatedTime);
     if (empty($oldestDateToProcessForNewSegment)) {
         return $date;
     }
     // if the start date for the archiving request is before the minimum date allowed for processing this segment,
     // use the minimum allowed date as the start date
     $periodObj = PeriodFactory::build($period, $date);
     if ($periodObj->getDateStart()->getTimestamp() < $oldestDateToProcessForNewSegment->getTimestamp()) {
         $this->logger->debug("Start date of archiving request period ({start}) is older than configured oldest date to process for the segment.", array('start' => $periodObj->getDateStart()));
         $endDate = $periodObj->getDateEnd();
         // if the creation time of a segment is older than the end date of the archiving request range, we cannot
         // blindly rewrite the date string, since the resulting range would be incorrect. instead we make the
         // start date equal to the end date, so less archiving occurs, and no fatal error occurs.
         if ($oldestDateToProcessForNewSegment->getTimestamp() > $endDate->getTimestamp()) {
             $this->logger->debug("Oldest date to process is greater than end date of archiving request period ({end}), so setting oldest date to end date.", array('end' => $endDate));
             $oldestDateToProcessForNewSegment = $endDate;
         }
         $date = $oldestDateToProcessForNewSegment->toString() . ',' . $endDate;
         $this->logger->debug("Archiving request date range changed to {date} w/ period {period}.", array('date' => $date, 'period' => $period));
     }
     return $date;
 }
 /**
  * The constructor
  * Initialize some local variables from the request
  * @param int $idSite
  * @param Date $date ($this->date from controller)
  * @param null|string $graphType
  * @throws Exception
  */
 public function __construct($idSite, $date, $graphType = 'graphEvolution')
 {
     $this->apiMethod = Common::getRequestVar('apiMethod', '', 'string');
     if (empty($this->apiMethod)) {
         throw new Exception("Parameter apiMethod not set.");
     }
     $this->label = DataTablePostProcessor::getLabelFromRequest($_GET);
     if (!is_array($this->label)) {
         throw new Exception("Expected label to be an array, got instead: " . $this->label);
     }
     $this->label = $this->label[0];
     if ($this->label === '') {
         throw new Exception("Parameter label not set.");
     }
     $this->period = Common::getRequestVar('period', '', 'string');
     PeriodFactory::checkPeriodIsEnabled($this->period);
     $this->idSite = $idSite;
     $this->graphType = $graphType;
     if ($this->period != 'range') {
         // handle day, week, month and year: display last X periods
         $end = $date->toString();
         list($this->date, $lastN) = EvolutionViz::getDateRangeAndLastN($this->period, $end);
     }
     $this->segment = \Piwik\API\Request::getRawSegmentFromRequest();
     $this->loadEvolutionReport();
 }
 private function createArchiveProcessorParamaters()
 {
     $oPeriod = PeriodFactory::makePeriodFromQueryParams('UTC', 'day', '2015-01-01');
     $segment = new Segment(false, array(1));
     $params = new Parameters(new Site(1), $oPeriod, $segment);
     return $params;
 }
Example #4
0
 public function testFactoryInvalid()
 {
     try {
         Period\Factory::build('inValid', Date::today());
     } catch (\Exception $e) {
         return;
     }
     $this->fail('Expected Exception not raised');
 }
Example #5
0
 /**
  * Creates a new ArchiveProcessor object
  *
  * @param string $periodLabel
  * @param string $dateLabel
  * @param string $siteTimezone
  * @return  \Core_ArchiveProcessorTest
  */
 private function _createArchiveProcessor($periodLabel, $dateLabel, $siteTimezone)
 {
     $site = $this->_createWebsite($siteTimezone);
     $date = Date::factory($dateLabel);
     $period = Period\Factory::build($periodLabel, $date);
     $segment = new Segment('', $site->getId());
     $params = new ArchiveProcessor\Parameters($site, $period, $segment);
     return new \Core_ArchiveProcessorTest($params);
 }
Example #6
0
 /**
  * @group        Benchmarks
  */
 public function testArchivingProcess()
 {
     if ($this->archivingLaunched) {
         echo "NOTE: Had to archive data, memory results will not be accurate. Run again for better results.";
     }
     Rules::$archivingDisabledByTests = true;
     $period = Period\Factory::build(self::$fixture->period, Date::factory(self::$fixture->date));
     $dateRange = $period->getDateStart() . ',' . $period->getDateEnd();
     API::getInstance()->get(self::$fixture->idSite, 'day', $dateRange);
 }
 /**
  * @param DataTable $table
  * @param int    $timezone  The timezone of the current selected site / the timezone of the labels
  * @param string $period    The requested period and date is needed to respect daylight saving etc.
  * @param string $date
  */
 public function __construct($table, $timezone, $period, $date)
 {
     $this->timezone = $timezone;
     $this->date = Period\Factory::build($period, $date)->getDateEnd();
     $self = $this;
     parent::__construct($table, function ($label) use($self) {
         $hour = str_pad($label, 2, 0, STR_PAD_LEFT);
         return $self->convertHourToUtc($hour);
     });
 }
Example #8
0
 /**
  * Return the number of visitors that visited every site in the given list for the
  * given date range. Includes the number of visitors that visited at least one site
  * and the number that visited every site.
  *
  * This data is calculated on demand, and for very large tables can take a long time
  * to run.
  *
  * See {@link Model\DistinctMetricsAggregator} for more information.
  *
  * @param string $idSite comma separated list of site IDs, ie, `"1,2,3"`
  * @param string $period
  * @param string $date
  * @return array Metrics **nb_total_visitors** and **nb_shared_visitors**.
  * @throws Exception if $idSite references zero sites or just one site.
  */
 public function getCommonVisitors($idSite, $period, $date, $segment = false)
 {
     if (empty($idSite)) {
         throw new Exception("No sites to get common visitors for.");
     }
     $idSites = Site::getIdSitesFromIdSitesString($idSite);
     Piwik::checkUserHasViewAccess($idSites);
     $segment = new Segment($segment, $idSites);
     $period = PeriodFactory::build($period, $date);
     return $this->distinctMetricsAggregator->getCommonVisitorCount($idSites, $period->getDateStart(), $period->getDateEnd(), $segment);
 }
 public function getTriggeredAlertsForPeriod($period, $date)
 {
     $piwikDate = Date::factory($date);
     $date = Period\Factory::build($period, $piwikDate);
     $db = $this->getDb();
     $sql = $this->getTriggeredAlertsSelectPart() . " WHERE  period = ? AND ts_triggered BETWEEN ? AND ?";
     $values = array($period, $date->getDateStart()->getDateStartUTC(), $date->getDateEnd()->getDateEndUTC());
     $alerts = $db->fetchAll($sql, $values);
     $alerts = $this->completeAlerts($alerts);
     return $alerts;
 }
Example #10
0
 public function getLastVisitsStart()
 {
     // hack, ensure we load today's visits by default
     $_GET['date'] = 'today';
     \Piwik\Period\Factory::checkPeriodIsEnabled('day');
     $_GET['period'] = 'day';
     $view = new View('@Live/getLastVisitsStart');
     $view->idSite = $this->idSite;
     $api = new Request("method=Live.getLastVisitsDetails&idSite={$this->idSite}&filter_limit=10&format=php&serialize=0&disable_generic_filters=1");
     $visitors = $api->process();
     $view->visitors = $visitors;
     return $this->render($view);
 }
Example #11
0
 public function setUp()
 {
     parent::setUp();
     $idSite = 1;
     if (!Fixture::siteCreated($idSite)) {
         Fixture::createWebsite('2014-01-01 00:00:00');
     }
     $site = new Site($idSite);
     $date = Date::factory('2012-01-01');
     $period = Period\Factory::build('month', $date);
     $segment = new Segment('', array($site->getId()));
     $params = new Parameters($site, $period, $segment);
     $this->logAggregator = new LogAggregator($params);
 }
Example #12
0
 private function createCollection($onlyOnePeriod = false, $onlyOneSite = false)
 {
     $periods = array(Period\Factory::build('day', '2012-12-12'), Period\Factory::build('day', '2012-12-13'));
     $dataType = 'numeric';
     $siteIds = array($this->site1, $this->site2);
     $dataNames = array('Name1', 'Name2');
     $defaultRow = array('default' => 1);
     if ($onlyOnePeriod) {
         $periods = array($periods[0]);
     }
     if ($onlyOneSite) {
         $siteIds = array($siteIds[0]);
     }
     return new DataCollection($dataNames, $dataType, $siteIds, $periods, $defaultRow);
 }
Example #13
0
 /**
  * General method to get transitions for an action
  *
  * @param $actionName
  * @param $actionType "url"|"title"
  * @param $idSite
  * @param $period
  * @param $date
  * @param bool $segment
  * @param bool $limitBeforeGrouping
  * @param string $parts
  * @return array
  * @throws Exception
  */
 public function getTransitionsForAction($actionName, $actionType, $idSite, $period, $date, $segment = false, $limitBeforeGrouping = false, $parts = 'all')
 {
     Piwik::checkUserHasViewAccess($idSite);
     // get idaction of the requested action
     $idaction = $this->deriveIdAction($actionName, $actionType);
     if ($idaction < 0) {
         throw new Exception('NoDataForAction');
     }
     // prepare log aggregator
     $segment = new Segment($segment, $idSite);
     $site = new Site($idSite);
     $period = Period\Factory::build($period, $date);
     $params = new ArchiveProcessor\Parameters($site, $period, $segment);
     $logAggregator = new LogAggregator($params);
     // prepare the report
     $report = array('date' => Period\Factory::build($period->getLabel(), $date)->getLocalizedShortString());
     $partsArray = explode(',', $parts);
     if ($parts == 'all' || in_array('internalReferrers', $partsArray)) {
         $this->addInternalReferrers($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping);
     }
     if ($parts == 'all' || in_array('followingActions', $partsArray)) {
         $includeLoops = $parts != 'all' && !in_array('internalReferrers', $partsArray);
         $this->addFollowingActions($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping, $includeLoops);
     }
     if ($parts == 'all' || in_array('externalReferrers', $partsArray)) {
         $this->addExternalReferrers($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping);
     }
     // derive the number of exits from the other metrics
     if ($parts == 'all') {
         $report['pageMetrics']['exits'] = $report['pageMetrics']['pageviews'] - $this->getTotalTransitionsToFollowingActions() - $report['pageMetrics']['loops'];
     }
     // replace column names in the data tables
     $reportNames = array('previousPages' => true, 'previousSiteSearches' => false, 'followingPages' => true, 'followingSiteSearches' => false, 'outlinks' => true, 'downloads' => true);
     foreach ($reportNames as $reportName => $replaceLabel) {
         if (isset($report[$reportName])) {
             $columnNames = array(Metrics::INDEX_NB_ACTIONS => 'referrals');
             if ($replaceLabel) {
                 $columnNames[Metrics::INDEX_NB_ACTIONS] = 'referrals';
             }
             $report[$reportName]->filter('ReplaceColumnNames', array($columnNames));
         }
     }
     return $report;
 }
Example #14
0
 /**
  * Returns datatable describing the number of visits for each day of the week.
  *
  * @param string $idSite The site ID. Cannot refer to multiple sites.
  * @param string $period The period type: day, week, year, range...
  * @param string $date The start date of the period. Cannot refer to multiple dates.
  * @param bool|string $segment The segment.
  * @throws Exception
  * @return DataTable
  */
 public function getByDayOfWeek($idSite, $period, $date, $segment = false)
 {
     Piwik::checkUserHasViewAccess($idSite);
     // metrics to query
     $metrics = Metrics::getVisitsMetricNames();
     unset($metrics[Metrics::INDEX_MAX_ACTIONS]);
     // disabled for multiple dates
     if (Period::isMultiplePeriod($date, $period)) {
         throw new Exception("VisitTime.getByDayOfWeek does not support multiple dates.");
     }
     // get metric data for every day within the supplied period
     $oPeriod = Period\Factory::makePeriodFromQueryParams(Site::getTimezoneFor($idSite), $period, $date);
     $dateRange = $oPeriod->getDateStart()->toString() . ',' . $oPeriod->getDateEnd()->toString();
     $archive = Archive::build($idSite, 'day', $dateRange, $segment);
     // disabled for multiple sites
     if (count($archive->getParams()->getIdSites()) > 1) {
         throw new Exception("VisitTime.getByDayOfWeek does not support multiple sites.");
     }
     $dataTable = $archive->getDataTableFromNumeric($metrics)->mergeChildren();
     // if there's no data for this report, don't bother w/ anything else
     if ($dataTable->getRowsCount() == 0) {
         return $dataTable;
     }
     // group by the day of the week (see below for dayOfWeekFromDate function)
     $dataTable->filter('GroupBy', array('label', __NAMESPACE__ . '\\dayOfWeekFromDate'));
     // create new datatable w/ empty rows, then add calculated datatable
     $rows = array();
     foreach (array(1, 2, 3, 4, 5, 6, 7) as $day) {
         $rows[] = array('label' => $day, 'nb_visits' => 0);
     }
     $result = new DataTable();
     $result->addRowsFromSimpleArray($rows);
     $result->addDataTable($dataTable);
     // set day of week integer as metadata
     $result->filter('ColumnCallbackAddMetadata', array('label', 'day_of_week'));
     // translate labels
     $result->filter('ColumnCallbackReplace', array('label', __NAMESPACE__ . '\\translateDayOfWeek'));
     // set datatable metadata for period start & finish
     $result->setMetadata('date_start', $oPeriod->getDateStart());
     $result->setMetadata('date_end', $oPeriod->getDateEnd());
     return $result;
 }
Example #15
0
 private function getDateRangeForFooterMessage()
 {
     // get query params
     $idSite = Common::getRequestVar('idSite', false);
     $date = Common::getRequestVar('date', false);
     $period = Common::getRequestVar('period', false);
     // create a period instance
     try {
         $oPeriod = Period\Factory::makePeriodFromQueryParams(Site::getTimezoneFor($idSite), $period, $date);
     } catch (\Exception $ex) {
         return '';
         // if query params are incorrect, forget about the footer message
     }
     // set the footer message using the period start & end date
     $start = $oPeriod->getDateStart()->toString();
     $end = $oPeriod->getDateEnd()->toString();
     if ($start == $end) {
         $dateRange = $start;
     } else {
         $dateRange = $start . " &ndash; " . $end;
     }
     return $dateRange;
 }
Example #16
0
 /**
  * Returns a new Archive instance that will query archive data for the given set of
  * sites and periods, using an optional Segment.
  *
  * This method uses data that is found in query parameters, so the parameters to this
  * function can be string values.
  *
  * If you want to create an Archive instance with an array of Period instances, use
  * {@link Archive::factory()}.
  *
  * @param string|int|array $idSites A single ID (eg, `'1'`), multiple IDs (eg, `'1,2,3'` or `array(1, 2, 3)`),
  *                                  or `'all'`.
  * @param string $period 'day', `'week'`, `'month'`, `'year'` or `'range'`
  * @param Date|string $strDate 'YYYY-MM-DD', magic keywords (ie, 'today'; {@link Date::factory()}
  *                             or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
  * @param bool|false|string $segment Segment definition or false if no segment should be used. {@link Piwik\Segment}
  * @param bool|false|string $_restrictSitesToLogin Used only when running as a scheduled task.
  * @param bool $skipAggregationOfSubTables Whether the archive, when it is processed, should also aggregate all sub-tables
  * @return Archive
  */
 public static function build($idSites, $period, $strDate, $segment = false, $_restrictSitesToLogin = false, $skipAggregationOfSubTables = false)
 {
     $websiteIds = Site::getIdSitesFromIdSitesString($idSites, $_restrictSitesToLogin);
     if (Period::isMultiplePeriod($strDate, $period)) {
         $oPeriod = Factory::build($period, $strDate);
         $allPeriods = $oPeriod->getSubperiods();
     } else {
         $timezone = count($websiteIds) == 1 ? Site::getTimezoneFor($websiteIds[0]) : false;
         $oPeriod = Factory::makePeriodFromQueryParams($timezone, $period, $strDate);
         $allPeriods = array($oPeriod);
     }
     $segment = new Segment($segment, $websiteIds);
     $idSiteIsAll = $idSites == self::REQUEST_ALL_WEBSITES_FLAG;
     $isMultipleDate = Period::isMultiplePeriod($strDate, $period);
     return Archive::factory($segment, $allPeriods, $websiteIds, $idSiteIsAll, $isMultipleDate, $skipAggregationOfSubTables);
 }
Example #17
0
 /**
  * @return array
  */
 private function getPeriodsToProcess()
 {
     $this->restrictToPeriods = array_intersect($this->restrictToPeriods, $this->getDefaultPeriodsToProcess());
     $this->restrictToPeriods = array_intersect($this->restrictToPeriods, PeriodFactory::getPeriodsEnabledForAPI());
     return $this->restrictToPeriods;
 }
Example #18
0
 /**
  * When tracking data in the past (using Tracking API), this function
  * can be used to invalidate reports for the idSites and dates where new data
  * was added.
  * DEV: If you call this API, the UI should display the data correctly, but will process
  *      in real time, which could be very slow after large data imports.
  *      After calling this function via REST, you can manually force all data
  *      to be reprocessed by visiting the script as the Super User:
  *      http://example.net/piwik/misc/cron/archive.php?token_auth=$SUPER_USER_TOKEN_AUTH_HERE
  * REQUIREMENTS: On large piwik setups, you will need in PHP configuration: max_execution_time = 0
  *    We recommend to use an hourly schedule of the script.
  *    More information: http://piwik.org/setup-auto-archiving/
  *
  * @param string $idSites Comma separated list of idSite that have had data imported for the specified dates
  * @param string $dates Comma separated list of dates to invalidate for all these websites
  * @throws Exception
  * @return array
  */
 public function invalidateArchivedReports($idSites, $dates)
 {
     $idSites = Site::getIdSitesFromIdSitesString($idSites);
     if (empty($idSites)) {
         throw new Exception("Specify a value for &idSites= as a comma separated list of website IDs, for which your token_auth has 'admin' permission");
     }
     Piwik::checkUserHasAdminAccess($idSites);
     // Ensure the specified dates are valid
     $toInvalidate = $invalidDates = array();
     $dates = explode(',', trim($dates));
     $dates = array_unique($dates);
     foreach ($dates as $theDate) {
         $theDate = trim($theDate);
         try {
             $date = Date::factory($theDate);
         } catch (Exception $e) {
             $invalidDates[] = $theDate;
             continue;
         }
         if ($date->toString() == $theDate) {
             $toInvalidate[] = $date;
         } else {
             $invalidDates[] = $theDate;
         }
     }
     // If using the feature "Delete logs older than N days"...
     $purgeDataSettings = PrivacyManager::getPurgeDataSettings();
     $logsAreDeletedBeforeThisDate = $purgeDataSettings['delete_logs_schedule_lowest_interval'];
     $logsDeleteEnabled = $purgeDataSettings['delete_logs_enable'];
     $minimumDateWithLogs = false;
     if ($logsDeleteEnabled && $logsAreDeletedBeforeThisDate) {
         $minimumDateWithLogs = Date::factory('today')->subDay($logsAreDeletedBeforeThisDate);
     }
     // Given the list of dates, process which tables they should be deleted from
     $minDate = false;
     $warningDates = $processedDates = array();
     /* @var $date Date */
     foreach ($toInvalidate as $date) {
         // we should only delete reports for dates that are more recent than N days
         if ($minimumDateWithLogs && $date->isEarlier($minimumDateWithLogs)) {
             $warningDates[] = $date->toString();
         } else {
             $processedDates[] = $date->toString();
         }
         $month = $date->toString('Y_m');
         // For a given date, we must invalidate in the monthly archive table
         $datesByMonth[$month][] = $date->toString();
         // But also the year stored in January
         $year = $date->toString('Y_01');
         $datesByMonth[$year][] = $date->toString();
         // but also weeks overlapping several months stored in the month where the week is starting
         /* @var $week Week */
         $week = Period\Factory::build('week', $date);
         $weekAsString = $week->getDateStart()->toString('Y_m');
         $datesByMonth[$weekAsString][] = $date->toString();
         // Keep track of the minimum date for each website
         if ($minDate === false || $date->isEarlier($minDate)) {
             $minDate = $date;
         }
     }
     if (empty($minDate)) {
         throw new Exception("Check the 'dates' parameter is a valid date.");
     }
     // In each table, invalidate day/week/month/year containing this date
     $archiveTables = ArchiveTableCreator::getTablesArchivesInstalled();
     foreach ($archiveTables as $table) {
         // Extract Y_m from table name
         $suffix = ArchiveTableCreator::getDateFromTableName($table);
         if (!isset($datesByMonth[$suffix])) {
             continue;
         }
         // Dates which are to be deleted from this table
         $datesToDeleteInTable = $datesByMonth[$suffix];
         // Build one statement to delete all dates from the given table
         $sql = $bind = array();
         $datesToDeleteInTable = array_unique($datesToDeleteInTable);
         foreach ($datesToDeleteInTable as $dateToDelete) {
             $sql[] = '(date1 <= ? AND ? <= date2)';
             $bind[] = $dateToDelete;
             $bind[] = $dateToDelete;
         }
         $sql = implode(" OR ", $sql);
         $query = "DELETE FROM {$table} " . " WHERE ( {$sql} ) " . " AND idsite IN (" . implode(",", $idSites) . ")";
         Db::query($query, $bind);
     }
     \Piwik\Plugins\SitesManager\API::getInstance()->updateSiteCreatedTime($idSites, $minDate);
     // Force to re-process data for these websites in the next cron core:archive command run
     $invalidatedIdSites = self::getWebsiteIdsToInvalidate();
     $invalidatedIdSites = array_merge($invalidatedIdSites, $idSites);
     $invalidatedIdSites = array_unique($invalidatedIdSites);
     $invalidatedIdSites = array_values($invalidatedIdSites);
     Option::set(self::OPTION_INVALIDATED_IDSITES, serialize($invalidatedIdSites));
     Site::clearCache();
     $output = array();
     // output logs
     if ($warningDates) {
         $output[] = 'Warning: the following Dates have not been invalidated, because they are earlier than your Log Deletion limit: ' . implode(", ", $warningDates) . "\n The last day with logs is " . $minimumDateWithLogs . ". " . "\n Please disable 'Delete old Logs' or set it to a higher deletion threshold (eg. 180 days or 365 years).'.";
     }
     $output[] = "Success. The following dates were invalidated successfully: " . implode(", ", $processedDates);
     return $output;
 }
Example #19
0
 /**
  * Sends the http headers for csv file
  */
 protected function renderHeader()
 {
     $fileName = 'Piwik ' . Piwik::translate('General_Export');
     $period = Common::getRequestVar('period', false);
     $date = Common::getRequestVar('date', false);
     if ($period || $date) {
         if ($period == 'range') {
             $period = new Range($period, $date);
         } else {
             if (strpos($date, ',') !== false) {
                 $period = new Range('range', $date);
             } else {
                 $period = Period\Factory::build($period, Date::factory($date));
             }
         }
         $prettyDate = $period->getLocalizedLongString();
         $meta = $this->getApiMetaData();
         $fileName .= ' _ ' . $meta['name'] . ' _ ' . $prettyDate . '.csv';
     }
     // silent fail otherwise unit tests fail
     Common::sendHeader('Content-Disposition: attachment; filename="' . $fileName . '"', true);
     ProxyHttp::overrideCacheControlHeaders();
 }
 private function getPrettyDateForSite($datetime, $period, $timezone)
 {
     $date = Date::factory($datetime, $timezone);
     // we ran the alerts for the period before...
     $date = $date->subPeriod(1, $period);
     $period = Period\Factory::build($period, $date);
     $prettyDate = $period->getLocalizedShortString();
     return $prettyDate;
 }
Example #21
0
 /**
  * @param $period
  * @return bool|int
  */
 private function getPeriodId($period)
 {
     if (!empty($period)) {
         $period = Period\Factory::build($period, Date::today());
     }
     $invalidateForPeriod = $period ? $period->getId() : false;
     return $invalidateForPeriod;
 }
 public function getProcessedReport($idSite, $period, $date, $apiModule, $apiAction, $segment = false, $apiParameters = false, $idGoal = false, $language = false, $showTimer = true, $hideMetricsDoc = false, $idSubtable = false, $showRawMetrics = false, $formatMetrics = null)
 {
     $timer = new Timer();
     if (empty($apiParameters)) {
         $apiParameters = array();
     }
     if (!empty($idGoal) && empty($apiParameters['idGoal'])) {
         $apiParameters['idGoal'] = $idGoal;
     }
     // Is this report found in the Metadata available reports?
     $reportMetadata = $this->getMetadata($idSite, $apiModule, $apiAction, $apiParameters, $language, $period, $date, $hideMetricsDoc, $showSubtableReports = true);
     if (empty($reportMetadata)) {
         throw new Exception("Requested report {$apiModule}.{$apiAction} for Website id={$idSite} not found in the list of available reports. \n");
     }
     $reportMetadata = reset($reportMetadata);
     // Generate Api call URL passing custom parameters
     $parameters = array_merge($apiParameters, array('method' => $apiModule . '.' . $apiAction, 'idSite' => $idSite, 'period' => $period, 'date' => $date, 'format' => 'original', 'serialize' => '0', 'language' => $language, 'idSubtable' => $idSubtable));
     if (!empty($segment)) {
         $parameters['segment'] = $segment;
     }
     if (!empty($reportMetadata['processedMetrics']) && !empty($reportMetadata['metrics']['nb_visits']) && @$reportMetadata['category'] != Piwik::translate('Goals_Ecommerce') && $apiModule !== 'MultiSites') {
         $deleteRowsWithNoVisits = empty($reportMetadata['constantRowsCount']) ? '1' : '0';
         $parameters['filter_add_columns_when_show_all_columns'] = $deleteRowsWithNoVisits;
     }
     $url = Url::getQueryStringFromParameters($parameters);
     $request = new Request($url);
     try {
         /** @var DataTable */
         $dataTable = $request->process();
     } catch (Exception $e) {
         throw new Exception("API returned an error: " . $e->getMessage() . " at " . basename($e->getFile()) . ":" . $e->getLine() . "\n");
     }
     list($newReport, $columns, $rowsMetadata, $totals) = $this->handleTableReport($idSite, $dataTable, $reportMetadata, $showRawMetrics, $formatMetrics);
     foreach ($columns as &$name) {
         $name = ucfirst($name);
     }
     $website = new Site($idSite);
     $period = Period\Factory::build($period, $date);
     $period = $period->getLocalizedLongString();
     $return = array('website' => $website->getName(), 'prettyDate' => $period, 'metadata' => $reportMetadata, 'columns' => $columns, 'reportData' => $newReport, 'reportMetadata' => $rowsMetadata, 'reportTotal' => $totals);
     if ($showTimer) {
         $return['timerMillis'] = $timer->getTimeMs(0);
     }
     return $return;
 }
Example #23
0
 private function createArchiveBlobEntry($date, $blobs)
 {
     $oPeriod = PeriodFactory::makePeriodFromQueryParams('UTC', 'day', $date);
     $segment = new Segment(false, array(1));
     $params = new Parameters(new Site(1), $oPeriod, $segment);
     $writer = new ArchiveWriter($params, false);
     $writer->initNewArchive();
     foreach ($blobs as $name => $blob) {
         $writer->insertBlobRecord($name, $blob);
     }
     $writer->finalizeArchive();
 }
Example #24
0
 /**
  * Returns start & end dates for the range described by a period and optional lastN
  * argument.
  *
  * @param string|bool $date The start date of the period (or the date range of a range
  *                           period).
  * @param string $period The period type ('day', 'week', 'month', 'year' or 'range').
  * @param bool|int $lastN Whether to include the last N periods in the range or not.
  *                         Ignored if period == range.
  *
  * @return Date[]   array of Date objects or array(false, false)
  * @ignore
  */
 public static function getDateRangeForPeriod($date, $period, $lastN = false)
 {
     if ($date === false) {
         return array(false, false);
     }
     // if the range is just a normal period (or the period is a range in which case lastN is ignored)
     if ($lastN === false || $period == 'range') {
         if ($period == 'range') {
             $oPeriod = new Range('day', $date);
         } else {
             $oPeriod = Period\Factory::build($period, Date::factory($date));
         }
         $startDate = $oPeriod->getDateStart();
         $endDate = $oPeriod->getDateEnd();
     } else {
         list($date, $lastN) = EvolutionViz::getDateRangeAndLastN($period, $date, $lastN);
         list($startDate, $endDate) = explode(',', $date);
         $startDate = Date::factory($startDate);
         $endDate = Date::factory($endDate);
     }
     return array($startDate, $endDate);
 }
Example #25
0
 /**
  * @param array $reports
  * @param array $info
  * @return mixed
  */
 public function getReportMetadata(&$reports, $info)
 {
     $idSites = $info['idSites'];
     // If only one website is selected, we add the Graph URL
     if (count($idSites) != 1) {
         return;
     }
     $idSite = reset($idSites);
     // in case API.getReportMetadata was not called with date/period we use sane defaults
     if (empty($info['period'])) {
         $info['period'] = 'day';
     }
     if (empty($info['date'])) {
         $info['date'] = 'today';
     }
     // need two sets of period & date, one for single period graphs, one for multiple periods graphs
     if (Period::isMultiplePeriod($info['date'], $info['period'])) {
         $periodForMultiplePeriodGraph = $info['period'];
         $dateForMultiplePeriodGraph = $info['date'];
         $periodForSinglePeriodGraph = 'range';
         $dateForSinglePeriodGraph = $info['date'];
     } else {
         $periodForSinglePeriodGraph = $info['period'];
         $dateForSinglePeriodGraph = $info['date'];
         $piwikSite = new Site($idSite);
         if ($periodForSinglePeriodGraph == 'range') {
             // for period=range, show the configured sub-periods
             $periodForMultiplePeriodGraph = Config::getInstance()->General['graphs_default_period_to_plot_when_period_range'];
             $dateForMultiplePeriodGraph = $dateForSinglePeriodGraph;
         } else {
             if ($info['period'] == 'day' || !Config::getInstance()->General['graphs_show_evolution_within_selected_period']) {
                 // for period=day, always show the last n days
                 // if graphs_show_evolution_within_selected_period=false, show the last n periods
                 $periodForMultiplePeriodGraph = $periodForSinglePeriodGraph;
                 $dateForMultiplePeriodGraph = Range::getRelativeToEndDate($periodForSinglePeriodGraph, 'last' . self::GRAPH_EVOLUTION_LAST_PERIODS, $dateForSinglePeriodGraph, $piwikSite);
             } else {
                 // if graphs_show_evolution_within_selected_period=true, show the days within the period
                 // (except if the period is day, see above)
                 $periodForMultiplePeriodGraph = 'day';
                 $period = PeriodFactory::build($info['period'], $info['date']);
                 $start = $period->getDateStart()->toString();
                 $end = $period->getDateEnd()->toString();
                 $dateForMultiplePeriodGraph = $start . ',' . $end;
             }
         }
     }
     $token_auth = Common::getRequestVar('token_auth', false);
     $segment = Request::getRawSegmentFromRequest();
     /** @var Scheduler $scheduler */
     $scheduler = StaticContainer::getContainer()->get('Piwik\\Scheduler\\Scheduler');
     $isRunningTask = $scheduler->isRunningTask();
     // add the idSubtable if it exists
     $idSubtable = Common::getRequestVar('idSubtable', false);
     $urlPrefix = "index.php?";
     foreach ($reports as &$report) {
         $reportModule = $report['module'];
         $reportAction = $report['action'];
         $reportUniqueId = $reportModule . '_' . $reportAction;
         $parameters = array();
         $parameters['module'] = 'API';
         $parameters['method'] = 'ImageGraph.get';
         $parameters['idSite'] = $idSite;
         $parameters['apiModule'] = $reportModule;
         $parameters['apiAction'] = $reportAction;
         if (!empty($token_auth)) {
             $parameters['token_auth'] = $token_auth;
         }
         // Forward custom Report parameters to the graph URL
         if (!empty($report['parameters'])) {
             $parameters = array_merge($parameters, $report['parameters']);
         }
         if (empty($report['dimension'])) {
             $parameters['period'] = $periodForMultiplePeriodGraph;
             $parameters['date'] = $dateForMultiplePeriodGraph;
         } else {
             $parameters['period'] = $periodForSinglePeriodGraph;
             $parameters['date'] = $dateForSinglePeriodGraph;
         }
         if ($idSubtable !== false) {
             $parameters['idSubtable'] = $idSubtable;
         }
         if (!empty($_GET['_restrictSitesToLogin']) && $isRunningTask) {
             $parameters['_restrictSitesToLogin'] = $_GET['_restrictSitesToLogin'];
         }
         if (!empty($segment)) {
             $parameters['segment'] = $segment;
         }
         $report['imageGraphUrl'] = $urlPrefix . Url::getQueryStringFromParameters($parameters);
         // thanks to API.getRowEvolution, reports with dimensions can now be plotted using an evolution graph
         // however, most reports with a fixed set of dimension values are excluded
         // this is done so Piwik Mobile and Scheduled Reports do not display them
         $reportWithDimensionsSupportsEvolution = empty($report['constantRowsCount']) || in_array($reportUniqueId, self::$CONSTANT_ROW_COUNT_REPORT_EXCEPTIONS);
         $reportSupportsEvolution = !in_array($reportUniqueId, self::$REPORTS_DISABLED_EVOLUTION_GRAPH);
         if ($reportSupportsEvolution && $reportWithDimensionsSupportsEvolution) {
             $parameters['period'] = $periodForMultiplePeriodGraph;
             $parameters['date'] = $dateForMultiplePeriodGraph;
             $report['imageGraphEvolutionUrl'] = $urlPrefix . Url::getQueryStringFromParameters($parameters);
         }
     }
 }
Example #26
0
 /**
  * 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';
     }
     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;
 }
Example #27
0
 /**
  * Returns the pretty date representation
  *
  * @param $date string
  * @param $period string
  * @return string Pretty date
  */
 public static function getPrettyDate($date, $period)
 {
     return self::getCalendarPrettyDate(Period\Factory::build($period, Date::factory($date)));
 }
Example #28
0
 /**
  * @deprecated Use Factory::build instead
  * @param $period
  * @param $date
  * @return Period
  */
 public static function factory($period, $date)
 {
     return Factory::build($period, $date);
 }
 private function insertArchiveRow($idSite, $date, $periodLabel)
 {
     $periodObject = \Piwik\Period\Factory::build($periodLabel, $date);
     $dateStart = $periodObject->getDateStart();
     $dateEnd = $periodObject->getDateEnd();
     $table = ArchiveTableCreator::getNumericTable($dateStart);
     $idArchive = (int) Db::fetchOne("SELECT MAX(idarchive) FROM {$table} WHERE name LIKE 'done%'");
     $idArchive = $idArchive + 1;
     $periodId = Piwik::$idPeriods[$periodLabel];
     $doneFlag = 'done';
     if ($idArchive % 5 == 1) {
         $doneFlag = Rules::getDoneFlagArchiveContainsAllPlugins(self::$segment1);
     } else {
         if ($idArchive % 5 == 2) {
             $doneFlag .= '.VisitsSummary';
         } else {
             if ($idArchive % 5 == 3) {
                 $doneFlag = Rules::getDoneFlagArchiveContainsOnePlugin(self::$segment1, 'UserCountry');
             } else {
                 if ($idArchive % 5 == 4) {
                     $doneFlag = Rules::getDoneFlagArchiveContainsAllPlugins(self::$segment2);
                 }
             }
         }
     }
     $sql = "INSERT INTO {$table} (idarchive, name, idsite, date1, date2, period, ts_archived)\n                     VALUES ({$idArchive}, 'nb_visits', {$idSite}, '{$dateStart}', '{$dateEnd}', {$periodId}, NOW()),\n                            ({$idArchive}, '{$doneFlag}', {$idSite}, '{$dateStart}', '{$dateEnd}', {$periodId}, NOW())";
     Db::query($sql);
 }
Example #30
0
 /**
  * Adds new subperiods
  *
  * @param Date $startDate
  * @param Date $endDate
  * @param string $period
  */
 protected function fillArraySubPeriods($startDate, $endDate, $period)
 {
     $arrayPeriods = array();
     $endSubperiod = Period\Factory::build($period, $endDate);
     $arrayPeriods[] = $endSubperiod;
     // set end date to start of end period since we're comparing against start date.
     $endDate = $endSubperiod->getDateStart();
     while ($endDate->isLater($startDate)) {
         $endDate = $endDate->addPeriod(-1, $period);
         $subPeriod = Period\Factory::build($period, $endDate);
         $arrayPeriods[] = $subPeriod;
     }
     $arrayPeriods = array_reverse($arrayPeriods);
     foreach ($arrayPeriods as $period) {
         $this->addSubperiod($period);
     }
 }