芝麻web文件管理V1.00
编辑当前文件:/home/mgatv524/public_html/avenida/views/Report.tar
DistributionReport.php 0000644 00000132103 14716415152 0011136 0 ustar 00 setCommonDependencies($state, $store, $timeSeriesStore, $log, $config, $date, $sanitizer); } /** @inheritdoc */ public function setFactories($container) { $this->displayFactory = $container->get('displayFactory'); $this->mediaFactory = $container->get('mediaFactory'); $this->layoutFactory = $container->get('layoutFactory'); $this->savedReportFactory = $container->get('savedReportFactory'); $this->userFactory = $container->get('userFactory'); $this->displayGroupFactory = $container->get('displayGroupFactory'); $this->reportService = $container->get('reportService'); return $this; } /** @inheritdoc */ public function getReportChartScript($results) { $labels = str_replace('"', "'", $results['chartData']['labels']); $countData = str_replace('"', "'", $results['chartData']['countData']); $durationData = str_replace('"', "'", $results['chartData']['durationData']); return "{type:'bar',data:{labels:".$labels.", datasets:[{label:'Total duration',yAxisID:'Duration',data:".$durationData."},{ label: 'Total count', yAxisID:'Count',borderColor: 'rgb(240,93,41, 0.8)', data: ".$countData.", type:'line', fill: 'false'}]}, options: { scales: { yAxes: [{ id: 'Duration', type: 'linear', position: 'left', display: true, scaleLabel: { display: true, labelString: 'Duration(s)' }, ticks: { beginAtZero:true } }, { id: 'Count', type: 'linear', position: 'right', display: true, scaleLabel: { display: true, labelString: 'Count' }, ticks: { beginAtZero:true } }] }, maintainAspectRatio: true, }}"; } /** @inheritdoc */ public function getReportEmailTemplate() { return 'distribution-email-template.twig'; } /** @inheritdoc */ public function getReportForm() { return [ 'template' => 'distribution-report-form', 'data' => [ 'fromDate' => $this->getDate()->getLocalDate(time() - (86400 * 35)), 'fromDateOneDay' => $this->getDate()->getLocalDate(time() - 86400), 'toDate' => $this->getDate()->getLocalDate(), 'availableReports' => $this->reportService->listReports() ] ]; } /** @inheritdoc */ public function getReportScheduleFormData() { $type = $this->getSanitizer()->getParam('type', ''); if ($type == 'layout') { $selectedId = $this->getSanitizer()->getParam('layoutId', null); $title = __('Add Report Schedule for '). $type. ' - '. $this->layoutFactory->getById($selectedId)->layout; } else if ($type == 'media') { $selectedId = $this->getSanitizer()->getParam('mediaId', null); $title = __('Add Report Schedule for '). $type. ' - '. $this->mediaFactory->getById($selectedId)->name; } else if ($type == 'event') { $selectedId = 0; // we only need eventTag $eventTag = $this->getSanitizer()->getParam('eventTag', null); $title = __('Add Report Schedule for '). $type. ' - '. $eventTag; } $data = []; $data['formTitle'] = $title; $data['hiddenFields'] = json_encode([ 'type' => $type, 'selectedId' => (int) $selectedId, 'eventTag' => isset($eventTag) ? $eventTag : null ]); $data['reportName'] = 'distributionReport'; return [ 'template' => 'distribution-schedule-form-add', 'data' => $data ]; } /** @inheritdoc */ public function setReportScheduleFormData() { $filter = $this->getSanitizer()->getString('filter'); $groupByFilter = $this->getSanitizer()->getString('groupByFilter'); $displayId = $this->getSanitizer()->getString('displayId'); $hiddenFields = json_decode($this->getSanitizer()->getParam('hiddenFields', null), true); $type = $hiddenFields['type']; $selectedId = $hiddenFields['selectedId']; $eventTag = $hiddenFields['eventTag']; $filterCriteria['displayId'] = $displayId; $filterCriteria['type'] = $type; if ($type == 'layout') { $filterCriteria['layoutId'] = $selectedId; } else if ($type == 'media') { $filterCriteria['mediaId'] = $selectedId; } else if ($type == 'event') { $filterCriteria['eventTag'] = $eventTag; } $filterCriteria['filter'] = $filter; $schedule = ''; if ($filter == 'daily') { $schedule = ReportSchedule::$SCHEDULE_DAILY; $filterCriteria['reportFilter'] = 'yesterday'; $filterCriteria['groupByFilter'] = $groupByFilter; } else if ($filter == 'weekly') { $schedule = ReportSchedule::$SCHEDULE_WEEKLY; $filterCriteria['reportFilter'] = 'lastweek'; $filterCriteria['groupByFilter'] = $groupByFilter; } else if ($filter == 'monthly') { $schedule = ReportSchedule::$SCHEDULE_MONTHLY; $filterCriteria['reportFilter'] = 'lastmonth'; $filterCriteria['groupByFilter'] = $groupByFilter; } else if ($filter == 'yearly') { $schedule = ReportSchedule::$SCHEDULE_YEARLY; $filterCriteria['reportFilter'] = 'lastyear'; $filterCriteria['groupByFilter'] = $groupByFilter; } $filterCriteria['sendEmail'] = $this->getSanitizer()->getCheckbox('sendEmail'); $filterCriteria['nonusers'] = $this->getSanitizer()->getString('nonusers'); // Return return [ 'filterCriteria' => json_encode($filterCriteria), 'schedule' => $schedule ]; } /** @inheritdoc */ public function generateSavedReportName($filterCriteria) { if ($filterCriteria['type'] == 'layout') { try { $layout = $this->layoutFactory->getById($filterCriteria['layoutId']); } catch (NotFoundException $error) { // Get the campaign ID $campaignId = $this->layoutFactory->getCampaignIdFromLayoutHistory($filterCriteria['layoutId']); $layoutId = $this->layoutFactory->getLatestLayoutIdFromLayoutHistory($campaignId); $layout = $this->layoutFactory->getById($layoutId); } $saveAs = __(ucfirst($filterCriteria['filter']). ' report for') . ' Layout '. $layout->layout; } else if ($filterCriteria['type'] == 'media') { try { $media = $this->mediaFactory->getById($filterCriteria['mediaId']); $saveAs = __(ucfirst($filterCriteria['filter']). ' report for') . ' Media '. $media->name; } catch (NotFoundException $error) { $saveAs = 'Media ' . __('Not Found'); } } else if ($filterCriteria['type'] == 'event') { $saveAs = __(ucfirst($filterCriteria['filter']). ' report for') . ' Event '. $filterCriteria['eventTag']; } else { $saveAs = __(ucfirst($filterCriteria['filter']). ' report for') . ' Type '. $filterCriteria['type']; } if (!empty($filterCriteria['displayId'])) { // Get display try{ $displayName = $this->displayFactory->getById($filterCriteria['displayId'])->display; $saveAs .= ' (Display: '. $displayName . ')'; } catch (NotFoundException $error){ $saveAs .= ' (DisplayId: ' . __('Not Found') . ' )'; } } return $saveAs; } /** @inheritdoc */ public function getSavedReportResults($json, $savedReport) { // Return data to build chart return [ 'template' => 'distribution-report-preview', 'chartData' => [ 'savedReport' => $savedReport, 'generatedOn' => $this->dateService->parse($savedReport->generatedOn, 'U')->format('Y-m-d H:i:s'), 'periodStart' => isset($json['periodStart']) ? $json['periodStart'] : '', 'periodEnd' => isset($json['periodEnd']) ? $json['periodEnd'] : '', 'labels' => json_encode($json['labels']), 'countData' => json_encode($json['countData']), 'durationData' => json_encode($json['durationData']), 'backgroundColor' => json_encode($json['backgroundColor']), 'borderColor' => json_encode($json['borderColor']), ] ]; } /** @inheritdoc */ public function getResults($filterCriteria) { $this->getLog()->debug('Filter criteria: '. json_encode($filterCriteria, JSON_PRETTY_PRINT)); $type = strtolower($this->getSanitizer()->getString('type', $filterCriteria)); $layoutId = $this->getSanitizer()->getInt('layoutId', $filterCriteria); $mediaId = $this->getSanitizer()->getInt('mediaId', $filterCriteria); $eventTag = $this->getSanitizer()->getString('eventTag', $filterCriteria); $displayId = $this->getSanitizer()->getInt('displayId', $filterCriteria); $displayGroupId = $this->getSanitizer()->getInt('displayGroupId', $filterCriteria); // Get an array of display id this user has access to. $displayIds = []; // Get an array of display id this user has access to. foreach ($this->displayFactory->query() as $display) { $displayIds[] = $display->displayId; } // Set displayIds as [-1] if the user selected a display for which they don't have permission if ($displayId != 0) { if (!in_array($displayId, $displayIds)) { $displayIds = [-1]; } else { $displayIds = [$displayId]; } } if (count($displayIds) <= 0) { throw new InvalidArgumentException(__('No displays with View permissions'), 'displays'); } // Get an array of display groups this user has access to $displayGroupIds = []; foreach ($this->displayGroupFactory->query(null, ['isDisplaySpecific' => -1]) as $displayGroup) { $displayGroupIds[] = $displayGroup->displayGroupId; } if (count($displayGroupIds) <= 0) { throw new InvalidArgumentException(__('No display groups with View permissions'), 'displayGroup'); } // // From and To Date Selection // -------------------------- // Our report has a range filter which determins whether or not the user has to enter their own from / to dates // check the range filter first and set from/to dates accordingly. $reportFilter = $this->getSanitizer()->getString('reportFilter', $filterCriteria); // Use the current date as a helper $now = $this->getDate()->parse(); switch ($reportFilter) { case 'today': $fromDt = $now->copy()->startOfDay(); $toDt = $fromDt->copy()->addDay(); break; case 'yesterday': $fromDt = $now->copy()->startOfDay()->subDay(); $toDt = $now->copy()->startOfDay(); break; case 'thisweek': $fromDt = $now->copy()->startOfWeek(); $toDt = $fromDt->copy()->addWeek(); break; case 'thismonth': $fromDt = $now->copy()->startOfMonth(); $toDt = $fromDt->copy()->addMonth(); break; case 'thisyear': $fromDt = $now->copy()->startOfYear(); $toDt = $fromDt->copy()->addYear(); break; case 'lastweek': $fromDt = $now->copy()->startOfWeek()->subWeek(); $toDt = $fromDt->copy()->addWeek(); break; case 'lastmonth': $fromDt = $now->copy()->startOfMonth()->subMonth(); $toDt = $fromDt->copy()->addMonth(); break; case 'lastyear': $fromDt = $now->copy()->startOfYear()->subYear(); $toDt = $fromDt->copy()->addYear(); break; case '': default: // Expect dates to be provided. $fromDt = $this->getSanitizer()->getDate('statsFromDt', $this->getDate()->parse()->addDay(-1)); $fromDt->startOfDay(); $toDt = $this->getSanitizer()->getDate('statsToDt', $this->getDate()->parse()); $toDt->addDay()->startOfDay(); // What if the fromdt and todt are exactly the same? // in this case assume an entire day from midnight on the fromdt to midnight on the todt (i.e. add a day to the todt) if ($fromDt == $toDt) { $toDt->addDay(); } break; } // Use the group by filter provided // NB: this differs from the Summary Report where we set the group by according to the range selected $groupByFilter = $this->getSanitizer()->getString('groupByFilter', $filterCriteria); // // Get Results! // ------------- $timeSeriesStore = $this->getTimeSeriesStore()->getEngine(); if ($timeSeriesStore == 'mongodb') { $result = $this->getDistributionReportMongoDb($fromDt, $toDt, $groupByFilter, $displayIds, $displayGroupIds, $type, $layoutId, $mediaId, $eventTag); } else { $result = $this->getDistributionReportMySql($fromDt, $toDt, $groupByFilter, $displayIds, $displayGroupIds, $type, $layoutId, $mediaId, $eventTag); } // // Output Results // -------------- $labels = []; $countData = []; $durationData = []; $backgroundColor = []; $borderColor = []; // Format the results for output on a chart if (count($result) > 0) { foreach ($result['result'] as $row) { // Chart labels in xaxis $labels[] = $row['label']; $backgroundColor[] = 'rgb(95, 186, 218, 0.6)'; $borderColor[] = 'rgb(240,93,41, 0.8)'; $count = $this->getSanitizer()->int($row['NumberPlays']); $countData[] = ($count == '') ? 0 : $count; $duration = $this->getSanitizer()->int($row['Duration']); $durationData[] = ($duration == '') ? 0 : $duration; } } // Return data to build chart return [ 'periodStart' => $this->getDate()->getLocalDate($fromDt), 'periodEnd' => $this->getDate()->getLocalDate($toDt), 'labels' => $labels, 'countData' => $countData, 'durationData' => $durationData, 'backgroundColor' => $backgroundColor, 'borderColor' => $borderColor, ]; } /** * MySQL distribution report * @param \Jenssegers\Date\Date $fromDt The filter range from date * @param \Jenssegers\Date\Date $toDt The filter range to date * @param string $groupByFilter Grouping, byhour, bydayofweek and bydayofmonth * @param $displayIds * @param $displayGroupIds * @param $type * @param $layoutId * @param $mediaId * @param $eventTag * @return array */ private function getDistributionReportMySql($fromDt, $toDt, $groupByFilter, $displayIds, $displayGroupIds, $type, $layoutId, $mediaId, $eventTag) { // Only return something if we have the necessary options selected. if ( (($type == 'media') && ($mediaId != '')) || (($type == 'layout') && ($layoutId != '')) || (($type == 'event') && ($eventTag != '')) ) { // Create periods covering the from/to dates // ----------------------------------------- try { $periods = $this->getTemporaryPeriodsTable($fromDt, $toDt, $groupByFilter); } catch (InvalidArgumentException $invalidArgumentException) { return []; } // Join in stats // ------------- $select = ' SELECT start, end, periodsWithStats.id, periodsWithStats.label, SUM(count) as NumberPlays, CONVERT(SUM(periodsWithStats.actualDiff), SIGNED INTEGER) as Duration FROM ( SELECT *, GREATEST(periods.start, statStart, :fromDt) AS actualStart, LEAST(periods.end, statEnd, :toDt) AS actualEnd, LEAST(stat.duration, LEAST(periods.end, statEnd, :toDt) - GREATEST(periods.start, statStart, :fromDt)) AS actualDiff FROM `' . $periods . '` AS periods LEFT OUTER JOIN ( SELECT layout.Layout, IFNULL(`media`.name, IFNULL(`widgetoption`.value, `widget`.type)) AS Media, stat.mediaId, stat.`start` as statStart, stat.`end` as statEnd, stat.duration, stat.`count` FROM stat LEFT OUTER JOIN layout ON layout.layoutID = stat.layoutID LEFT OUTER JOIN `widget` ON `widget`.widgetId = stat.widgetId LEFT OUTER JOIN `widgetoption` ON `widgetoption`.widgetId = `widget`.widgetId AND `widgetoption`.type = \'attrib\' AND `widgetoption`.option = \'name\' LEFT OUTER JOIN `media` ON `media`.mediaId = `stat`.mediaId WHERE stat.type <> \'displaydown\' AND stat.start < :toDt AND stat.end >= :fromDt '; $params = [ 'fromDt' => $fromDt->format('U'), 'toDt' => $toDt->format('U') ]; // Displays if (count($displayIds) > 0) { $select .= ' AND stat.displayID IN (' . implode(',', $displayIds) . ') '; } // Type filter if (($type == 'layout') && ($layoutId != '')) { // Filter by Layout $select .= ' AND `stat`.type = \'layout\' AND `stat`.campaignId = (SELECT campaignId FROM layouthistory WHERE layoutId = :layoutId) '; $params['layoutId'] = $layoutId; } elseif (($type == 'media') && ($mediaId != '')) { // Filter by Media $select .= ' AND `stat`.type = \'media\' AND IFNULL(`media`.mediaId, 0) <> 0 AND `stat`.mediaId = :mediaId '; $params['mediaId'] = $mediaId; } elseif (($type == 'event') && ($eventTag != '')) { // Filter by Event $select .= ' AND `stat`.type = \'event\' AND `stat`.tag = :tag '; $params['tag'] = $eventTag; } $select .= ' ) stat ON statStart < periods.`end` AND statEnd > periods.`start` '; // Periods and Stats tables are joined, we should only have periods we're interested in, but it // wont hurt to restrict them $select .= ' WHERE periods.`start` >= :fromDt AND periods.`end` <= :toDt '; // Close out our containing view and group things together $select .= ' ) periodsWithStats GROUP BY periodsWithStats.id, periodsWithStats.label ORDER BY periodsWithStats.id '; return [ 'result' => $this->getStore()->select($select, $params), 'periodStart' => $fromDt->format('Y-m-d H:i:s'), 'periodEnd' => $toDt->format('Y-m-d H:i:s') ]; } else { return []; } } private function getDistributionReportMongoDb($fromDt, $toDt, $groupByFilter, $displayIds, $displayGroupIds, $type, $layoutId, $mediaId, $eventTag) { if ( (($type == 'media') && ($mediaId != '')) || (($type == 'layout') && ($layoutId != '')) || (($type == 'event') && ($eventTag != '')) ) { // Get the timezone $timezone = $this->getDate()->parse()->getTimezone()->getName(); $filterRangeStart = new UTCDateTime($fromDt->format('U') * 1000); $filterRangeEnd = new UTCDateTime($toDt->format('U') * 1000); $diffInDays = $toDt->diffInDays($fromDt); if ($groupByFilter == 'byhour') { $hour = 1; $input = range(0, 24 * $diffInDays - 1); // subtract 1 as we start from 0 $id = '$hour'; } elseif ($groupByFilter == 'bydayofweek') { $hour = 24; $input = range(0, $diffInDays - 1); $id = '$isoDayOfWeek'; } elseif ($groupByFilter == 'bydayofmonth') { $hour = 24; $input = range(0, $diffInDays - 1); $id = '$dayOfMonth'; } else { $this->getLog()->error('Unknown Grouping Selected ' . $groupByFilter); throw new InvalidArgumentException('Unknown Grouping ' . $groupByFilter, 'groupByFilter'); } // Dateparts for period generation $dateFromParts['month'] = $fromDt->month; $dateFromParts['year'] = $fromDt->year; $dateFromParts['day'] = $fromDt->day; $dateFromParts['hour'] = 0; // PERIODS QUERY $cursorPeriodQuery = [ [ '$addFields' => [ 'period_start' => [ '$dateFromParts' => [ 'year' => $dateFromParts['year'], 'month' => $dateFromParts['month'], 'day' => $dateFromParts['day'], 'hour' => $dateFromParts['hour'], 'timezone' => $timezone, ] ] ] ], [ '$project' => [ 'periods' => [ '$map' => [ 'input' => $input, 'as' => 'number', 'in' => [ 'start' => [ '$add' => [ '$period_start', [ '$multiply' => [ $hour * 3600000, '$$number' ] ] ] ], 'end' => [ '$add' => [ [ '$add' => [ '$period_start', [ '$multiply' => [ $hour * 3600000, '$$number' ] ] ] ] , $hour * 3600000 ] ], ] ] ] ] ], // periods needs to be unwind to merge next [ '$unwind' => '$periods' ], // replace the root to eliminate _id and get only periods [ '$replaceRoot' => [ 'newRoot' => '$periods' ] ], [ '$project' => [ 'start' => 1, 'end' => 1, 'id' => [ $id => [ 'date' => '$start', 'timezone'=> $timezone ] ], ] ], [ '$group' => [ '_id' => [ 'id' => '$id' ], 'start' => ['$first' => '$start'], 'end' => ['$first' => '$end'], 'id' => ['$first' => '$id'], ] ], [ '$match' => [ 'start' => [ '$lt' => $filterRangeEnd ], 'end' => [ '$gt' => $filterRangeStart ] ] ], [ '$sort' => ['id' => 1] ] ]; // Periods result $periods = $this->getTimeSeriesStore()->executeQuery(['collection' => $this->periodTable, 'query' => $cursorPeriodQuery]); // We extend the stat start and stat end so that we can push required periods for them if ( ($groupByFilter == 'bydayofweek') || ($groupByFilter == 'bydayofmonth') ) { $datePartStart = [ '$dateFromParts' => [ 'year' => [ '$year' => '$start' ], 'month' => [ '$month' => '$start' ], 'day' => [ '$dayOfMonth' => '$start' ], ] ]; $datePartEnd = [ '$dateFromParts' => [ 'year' => [ '$year' => '$end' ], 'month' => [ '$month' => '$end' ], 'day' => [ '$dayOfMonth' => '$end' ], ] ]; } else { // by hour $datePartStart = [ '$dateFromParts' => [ 'year' => [ '$year' => '$start' ], 'month' => [ '$month' => '$start' ], 'day' => [ '$dayOfMonth' => '$start' ], 'hour' => [ '$hour' => '$start' ], ] ]; $datePartEnd = [ '$dateFromParts' => [ 'year' => [ '$year' => '$end' ], 'month' => [ '$month' => '$end' ], 'day' => [ '$dayOfMonth' => '$end' ], 'hour' => [ '$hour' => '$end' ], ] ]; } $match = [ '$match' => [ 'start' => [ '$lt' => $filterRangeEnd ], 'end' => [ '$gt' => $filterRangeStart ], 'type' => $type, 'displayId' => [ '$in' => $displayIds ] ] ]; // Type filter if (($type == 'layout') && ($layoutId != '')) { // Get the campaign ID $campaignId = $this->layoutFactory->getCampaignIdFromLayoutHistory($layoutId); $match['$match']['campaignId'] = $campaignId; } elseif (($type == 'media') && ($mediaId != '')) { $match['$match']['mediaId'] = $mediaId; } elseif (($type == 'event') && ($eventTag != '')) { $match['$match']['eventName'] = $eventTag; } // STAT AGGREGATION QUERY $statQuery = [ $match, [ '$project' => [ 'count' => 1, 'duration' => 1, 'start' => [ '$dateFromParts' => [ 'year' => [ '$year' => [ 'date' => '$start', 'timezone' => $timezone, ] ], 'month' => [ '$month' => [ 'date' => '$start', 'timezone' => $timezone, ] ], 'day' => [ '$dayOfMonth' => [ 'date' => '$start', 'timezone' => $timezone, ] ], 'hour' => [ '$hour' => [ 'date' => '$start', 'timezone' => $timezone, ] ], 'minute' => [ '$minute' => [ 'date' => '$start', 'timezone' => $timezone, ] ], 'second' => [ '$second' => [ 'date' => '$start', 'timezone' => $timezone, ] ], ] ], 'end' => [ '$dateFromParts' => [ 'year' => [ '$year' => [ 'date' => '$end', 'timezone' => $timezone, ] ], 'month' => [ '$month' => [ 'date' => '$end', 'timezone' => $timezone, ] ], 'day' => [ '$dayOfMonth' => [ 'date' => '$end', 'timezone' => $timezone, ] ], 'hour' => [ '$hour' => [ 'date' => '$end', 'timezone' => $timezone, ] ], 'minute' => [ '$minute' => [ 'date' => '$end', 'timezone' => $timezone, ] ], 'second' => [ '$second' => [ 'date' => '$end', 'timezone' => $timezone, ] ], ] ] ] ], [ '$addFields' => [ 'period_start_backward' => $datePartStart, 'period_end_forward' => [ '$add' => [ $datePartEnd, $hour * 3600000 ] ] ] ], [ '$project' => [ 'start' => 1, 'end' => 1, 'count' => 1, 'duration' => 1, 'period_start_backward' => 1, 'period_end_forward' => 1, 'range' => [ '$range' => [ 0, [ '$ceil' => [ '$divide' => [ [ '$subtract' => [ '$period_end_forward', '$period_start_backward' ] ], $hour * 3600000 ] ] ] ] ], 'period_start' => [ '$dateFromParts' => [ 'year' => [ '$year' => '$period_start_backward' ], 'month' => [ '$month' => '$period_start_backward' ], 'day' => [ '$dayOfMonth' => '$period_start_backward' ], 'hour' => [ '$hour' => '$period_start_backward' ], ] ] ] ], [ '$project' => [ 'start' => 1, 'end' => 1, 'count' => 1, 'duration' => 1, 'periods' => [ '$map' => [ 'input' => '$range', 'as' => 'number', 'in' => [ 'start' => [ '$add' => [ '$period_start', [ '$multiply' => [ $hour * 3600000, '$$number' ] ] ] ], 'end' => [ '$add' => [ [ '$add' => [ '$period_start', [ '$multiply' => [ $hour * 3600000, '$$number' ] ] ] ] , $hour * 3600000 ] ], ] ] ] ] ], [ '$unwind' => '$periods' ], [ '$match' => [ 'periods.start' => ['$lt' => $filterRangeEnd ], 'periods.end' => ['$gt' => $filterRangeStart ], ] ], [ '$project' => [ 'start' => 1, 'end' => 1, 'count' => 1, 'duration' => 1, 'period_start' => '$periods.start', 'period_end' => '$periods.end', 'id' => [ $id => [ 'date' => '$periods.start', 'timezone'=> 'UTC' ] ], 'actualStart' => [ '$max' => ['$start', '$periods.start', $filterRangeStart] ], 'actualEnd' => [ '$min' => ['$end', '$periods.end', $filterRangeEnd] ], 'actualDiff' => [ '$min' => [ '$duration', [ '$divide' => [ [ '$subtract' => [ ['$min' => ['$end', '$periods.end', $filterRangeEnd]], ['$max' => ['$start', '$periods.start', $filterRangeStart]] ] ], 1000 ] ] ] ], ] ], [ '$match' => [ '$expr' => [ '$lt' => ['$actualStart' , '$actualEnd' ], ] ] ], [ '$group' => [ '_id' => [ 'id' => '$id' ], 'period_start' => ['$first' => '$period_start'], 'period_end' => ['$first' => '$period_end'], 'NumberPlays' => ['$sum' => '$count'], 'Duration' => ['$sum' => '$actualDiff'], 'start' => ['$first' => '$start'], 'end' => ['$first' => '$end'], 'id' => ['$first' => '$id'], ] ], [ '$project' => [ 'start' => '$start', 'end' => '$end', 'period_start' => 1, 'period_end' => 1, 'NumberPlays' => 1, 'Duration' => 1, 'id' => 1, ] ], [ '$sort' => ['id' => 1] ] ]; // Stats result $results = $this->getTimeSeriesStore()->executeQuery(['collection' => $this->table, 'query' => $statQuery]); // Run period loop and map the stat result for each period $resultArray = []; $day = [ 1 => 'Mon', 2 => 'Tues', 3 => 'Wed', 4 => 'Thu', 5 => 'Fri', 6 => 'Sat', 7 => 'Sun']; foreach ($periods as $key => $period) { $id = $period['id']; if($groupByFilter == 'byhour'){ $label = $this->getDate()->parse($period['start']->toDateTime()->format('U'), 'U')->format('g:i A'); } elseif ($groupByFilter == 'bydayofweek') { $label = $day[$id]; } elseif ($groupByFilter == 'bydayofmonth') { $label = $this->getDate()->parse($period['start']->toDateTime()->format('U'), 'U')->format('d'); } $matched = false; foreach ($results as $k => $result) { if( $result['id'] == $period['id'] ) { $NumberPlays = $result['NumberPlays']; $Duration = $result['Duration']; $matched = true; break; } } $resultArray[$key]['id'] = $id; $resultArray[$key]['label'] = $label; if($matched == true) { $resultArray[$key]['NumberPlays'] = $NumberPlays; $resultArray[$key]['Duration'] = $Duration; } else { $resultArray[$key]['NumberPlays'] = 0; $resultArray[$key]['Duration'] = 0; } } $this->getLog()->debug('Period start: ' . $fromDt->format('Y-m-d H:i:s') . ' Period end: ' . $toDt->format('Y-m-d H:i:s')); return [ 'result' => $resultArray, 'periodStart' => $fromDt->format('Y-m-d H:i:s'), 'periodEnd' => $toDt->format('Y-m-d H:i:s') ]; } else { return []; } } } error_log; 0000644 00000110726 14716415152 0006571 0 ustar 00 [15-Sep-2023 18:36:31 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [18-Sep-2023 04:34:28 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [25-Sep-2023 16:08:56 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [25-Sep-2023 16:08:57 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [25-Sep-2023 16:08:59 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [26-Sep-2023 02:01:11 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [26-Sep-2023 02:01:14 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [26-Sep-2023 02:02:48 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [27-Sep-2023 00:55:20 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [27-Sep-2023 00:55:22 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [27-Sep-2023 00:55:23 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [27-Sep-2023 01:07:09 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [27-Sep-2023 01:07:13 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [27-Sep-2023 01:07:14 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [27-Sep-2023 08:18:27 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [12-Nov-2023 19:07:40 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [12-Nov-2023 19:07:47 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [12-Nov-2023 19:07:49 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [14-Nov-2023 21:41:56 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [14-Nov-2023 21:41:57 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [14-Nov-2023 21:42:01 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [15-Nov-2023 03:30:38 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [15-Nov-2023 03:30:44 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [15-Nov-2023 03:30:46 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [16-Nov-2023 02:41:13 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [16-Nov-2023 02:41:15 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [16-Nov-2023 02:41:37 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [28-Nov-2023 03:27:52 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [30-Nov-2023 19:19:17 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [08-Jan-2024 07:17:30 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [16-Jan-2024 07:13:12 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [25-Jan-2024 16:28:30 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [28-Jan-2024 21:49:08 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [05-Feb-2024 20:32:16 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [11-Feb-2024 01:47:22 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [11-Feb-2024 11:56:09 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [11-Feb-2024 13:46:14 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [21-Feb-2024 11:24:43 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [21-Feb-2024 11:24:44 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [21-Feb-2024 11:24:48 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [22-Feb-2024 03:43:44 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [27-Feb-2024 13:10:17 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [27-Feb-2024 13:10:23 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [27-Feb-2024 13:10:30 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [28-Feb-2024 19:04:58 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [06-Mar-2024 09:17:08 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [06-Mar-2024 21:48:27 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [11-Mar-2024 16:45:14 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [19-Mar-2024 13:26:26 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [19-Mar-2024 19:55:38 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [26-Mar-2024 01:22:10 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [02-Apr-2024 09:46:43 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [03-Apr-2024 00:13:08 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [03-Apr-2024 00:13:10 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [04-Apr-2024 11:45:03 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [04-Apr-2024 21:22:21 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [09-Apr-2024 07:57:42 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [09-Apr-2024 07:59:40 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [10-Apr-2024 17:24:56 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [12-Apr-2024 15:06:45 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [13-Apr-2024 04:34:15 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [23-Apr-2024 23:36:24 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [25-Apr-2024 12:36:45 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [09-May-2024 11:34:29 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [11-May-2024 01:39:45 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [14-May-2024 04:53:14 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [14-May-2024 08:21:32 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [16-May-2024 21:59:52 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [17-May-2024 11:55:37 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [19-May-2024 01:08:15 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [19-May-2024 01:08:23 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [19-May-2024 01:08:31 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [21-May-2024 10:23:43 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [21-May-2024 10:23:51 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [21-May-2024 10:23:59 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [21-May-2024 11:35:43 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [21-May-2024 11:35:51 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [21-May-2024 11:35:59 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [21-May-2024 12:46:11 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [21-May-2024 12:46:19 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [21-May-2024 12:46:27 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [27-May-2024 16:04:55 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [28-May-2024 05:06:25 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [03-Jun-2024 02:39:57 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [03-Jun-2024 05:05:06 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [08-Jun-2024 16:08:41 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [09-Jun-2024 05:59:56 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [19-Jun-2024 04:43:35 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [19-Jun-2024 18:32:02 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [23-Jun-2024 01:19:11 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [24-Jun-2024 00:17:08 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [25-Jun-2024 04:34:36 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [25-Jun-2024 10:25:24 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [25-Jun-2024 23:10:01 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [26-Jun-2024 07:28:34 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [26-Jun-2024 13:32:06 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [26-Jun-2024 17:01:20 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [27-Jun-2024 09:55:36 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [27-Jun-2024 18:21:22 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [28-Jun-2024 11:57:16 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [28-Jun-2024 22:47:11 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [30-Jun-2024 03:08:41 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [01-Jul-2024 01:11:38 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [01-Jul-2024 01:24:58 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [01-Jul-2024 01:27:51 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [01-Jul-2024 15:49:04 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [01-Jul-2024 17:30:10 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [01-Jul-2024 17:32:16 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [02-Jul-2024 00:08:57 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [02-Jul-2024 12:32:12 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [02-Jul-2024 23:46:05 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [02-Jul-2024 23:46:17 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [02-Jul-2024 23:47:04 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [05-Jul-2024 00:09:29 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [05-Jul-2024 08:05:08 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [05-Jul-2024 08:05:14 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [05-Jul-2024 08:05:15 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [07-Jul-2024 04:58:31 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [07-Jul-2024 16:02:12 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [11-Jul-2024 00:45:10 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [17-Jul-2024 17:26:46 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [18-Jul-2024 18:58:00 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [22-Jul-2024 09:26:58 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [22-Jul-2024 13:08:58 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [22-Jul-2024 13:09:02 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [24-Jul-2024 11:21:22 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [24-Jul-2024 11:21:30 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [24-Jul-2024 11:21:38 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [26-Jul-2024 03:23:57 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [27-Jul-2024 14:12:12 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [27-Jul-2024 14:19:43 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [01-Aug-2024 00:19:32 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [01-Aug-2024 21:19:12 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [02-Aug-2024 08:51:51 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [02-Aug-2024 09:54:15 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [02-Aug-2024 14:28:14 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [04-Aug-2024 18:30:32 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [07-Aug-2024 08:59:44 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [07-Aug-2024 17:57:23 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [09-Aug-2024 15:01:57 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [11-Aug-2024 02:48:22 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [13-Aug-2024 11:11:02 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [23-Aug-2024 05:01:54 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [26-Aug-2024 22:45:23 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [28-Aug-2024 06:56:28 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [29-Aug-2024 11:44:57 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [01-Sep-2024 20:24:06 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [02-Sep-2024 17:35:18 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [02-Sep-2024 18:32:32 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [02-Sep-2024 19:34:46 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [02-Sep-2024 21:16:39 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [03-Sep-2024 17:38:01 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [04-Sep-2024 00:43:08 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [04-Sep-2024 04:39:34 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [04-Sep-2024 06:12:10 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [07-Sep-2024 06:09:11 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [08-Sep-2024 00:00:22 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [08-Sep-2024 11:00:52 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [09-Sep-2024 11:24:44 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [12-Sep-2024 15:56:51 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [15-Sep-2024 01:05:04 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [16-Sep-2024 12:50:02 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [16-Sep-2024 12:50:10 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [16-Sep-2024 12:50:18 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [16-Sep-2024 13:39:48 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [16-Sep-2024 13:39:56 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [16-Sep-2024 13:40:04 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [16-Sep-2024 14:31:56 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [16-Sep-2024 14:32:04 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [16-Sep-2024 14:55:48 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [16-Sep-2024 14:55:55 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [16-Sep-2024 14:56:04 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [18-Sep-2024 19:16:25 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [18-Sep-2024 22:41:13 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [18-Sep-2024 22:53:25 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [18-Sep-2024 22:59:29 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [19-Sep-2024 17:45:08 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [20-Sep-2024 06:42:00 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [25-Sep-2024 03:01:54 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [27-Sep-2024 04:16:04 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [01-Oct-2024 03:26:34 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [02-Oct-2024 16:45:26 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [06-Oct-2024 07:47:08 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [06-Oct-2024 11:59:04 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [07-Oct-2024 01:48:56 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [07-Oct-2024 02:51:02 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [07-Oct-2024 04:55:53 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [08-Oct-2024 23:11:23 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [10-Oct-2024 13:09:51 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [11-Oct-2024 21:21:19 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [11-Oct-2024 21:47:05 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [13-Oct-2024 01:56:32 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [23-Oct-2024 06:10:57 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [28-Oct-2024 02:59:08 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [29-Oct-2024 02:41:01 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [02-Nov-2024 19:04:35 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [02-Nov-2024 19:04:43 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [02-Nov-2024 19:04:51 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [06-Nov-2024 21:02:03 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [09-Nov-2024 13:52:28 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [09-Nov-2024 14:04:47 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [09-Nov-2024 16:56:28 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [10-Nov-2024 01:32:16 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 [12-Nov-2024 00:02:23 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/DistributionReport.php on line 30 [12-Nov-2024 00:02:31 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/SummaryReport.php on line 28 [12-Nov-2024 00:02:39 America/Fortaleza] PHP Fatal error: Trait 'Xibo\Report\ReportTrait' not found in /home/mgatv524/public_html/edurocha/lib/Report/ProofOfPlay.php on line 31 SummaryReport.php 0000644 00000123334 14716415152 0010122 0 ustar 00 setCommonDependencies($state, $store, $timeSeriesStore, $log, $config, $date, $sanitizer); } /** @inheritDoc */ public function setFactories($container) { $this->displayFactory = $container->get('displayFactory'); $this->mediaFactory = $container->get('mediaFactory'); $this->layoutFactory = $container->get('layoutFactory'); $this->savedReportFactory = $container->get('savedReportFactory'); $this->reportService = $container->get('reportService'); return $this; } /** @inheritdoc */ public function getReportChartScript($results) { $labels = str_replace('"', "'", $results['chartData']['labels']); $countData = str_replace('"', "'", $results['chartData']['countData']); $durationData = str_replace('"', "'", $results['chartData']['durationData']); return "{type:'bar',data:{labels:".$labels.", datasets:[{label:'Total duration',yAxisID:'Duration',data:".$durationData."},{ label: 'Total count',yAxisID:'Count',borderColor: 'rgb(240,93,41, 0.8)', data: ".$countData.", type:'line', fill: 'false'}]}, options: { scales: { yAxes: [{ id: 'Duration', type: 'linear', position: 'left', display: true, scaleLabel: { display: true, labelString: 'Duration(s)' }, ticks: { beginAtZero:true } }, { id: 'Count', type: 'linear', position: 'right', display: true, scaleLabel: { display: true, labelString: 'Count' }, ticks: { beginAtZero:true } }] }, maintainAspectRatio: true, }}"; } /** @inheritdoc */ public function getReportEmailTemplate() { return 'summary-email-template.twig'; } /** @inheritdoc */ public function getReportForm() { return [ 'template' => 'summary-report-form', 'data' => [ 'fromDate' => $this->getDate()->getLocalDate(time() - (86400 * 35)), 'fromDateOneDay' => $this->getDate()->getLocalDate(time() - 86400), 'toDate' => $this->getDate()->getLocalDate(), 'availableReports' => $this->reportService->listReports() ] ]; } /** @inheritdoc */ public function getReportScheduleFormData() { $type = $this->getSanitizer()->getParam('type', ''); if ($type == 'layout') { $selectedId = $this->getSanitizer()->getParam('layoutId', null); $title = __('Add Report Schedule for '). $type. ' - '. $this->layoutFactory->getById($selectedId)->layout; } else if ($type == 'media') { $selectedId = $this->getSanitizer()->getParam('mediaId', null); $title = __('Add Report Schedule for '). $type. ' - '. $this->mediaFactory->getById($selectedId)->name; } else if ($type == 'event') { $selectedId = 0; // we only need eventTag $eventTag = $this->getSanitizer()->getParam('eventTag', null); $title = __('Add Report Schedule for '). $type. ' - '. $eventTag; } $data = ['filters' => []]; $data['filters'][] = ['name'=> 'Daily', 'filter'=> 'daily']; $data['filters'][] = ['name'=> 'Weekly', 'filter'=> 'weekly']; $data['filters'][] = ['name'=> 'Monthly', 'filter'=> 'monthly']; $data['filters'][] = ['name'=> 'Yearly', 'filter'=> 'yearly']; $data['formTitle'] = $title; $data['hiddenFields'] = json_encode([ 'type' => $type, 'selectedId' => (int) $selectedId, 'eventTag' => isset($eventTag) ? $eventTag : null ]); $data['reportName'] = 'summaryReport'; return [ 'template' => 'summary-report-schedule-form-add', 'data' => $data ]; } /** @inheritdoc */ public function setReportScheduleFormData() { $filter = $this->getSanitizer()->getString('filter'); $hiddenFields = json_decode($this->getSanitizer()->getParam('hiddenFields', null), true); $type = $hiddenFields['type']; $selectedId = $hiddenFields['selectedId']; $eventTag = $hiddenFields['eventTag']; $filterCriteria['type'] = $type; if ($type == 'layout') { $filterCriteria['layoutId'] = $selectedId; } else if ($type == 'media') { $filterCriteria['mediaId'] = $selectedId; } else if ($type == 'event') { $filterCriteria['eventTag'] = $eventTag; } $filterCriteria['filter'] = $filter; $schedule = ''; if ($filter == 'daily') { $schedule = ReportSchedule::$SCHEDULE_DAILY; $filterCriteria['reportFilter'] = 'yesterday'; } else if ($filter == 'weekly') { $schedule = ReportSchedule::$SCHEDULE_WEEKLY; $filterCriteria['reportFilter'] = 'lastweek'; } else if ($filter == 'monthly') { $schedule = ReportSchedule::$SCHEDULE_MONTHLY; $filterCriteria['reportFilter'] = 'lastmonth'; $filterCriteria['groupByFilter'] = 'byweek'; } else if ($filter == 'yearly') { $schedule = ReportSchedule::$SCHEDULE_YEARLY; $filterCriteria['reportFilter'] = 'lastyear'; $filterCriteria['groupByFilter'] = 'bymonth'; } $filterCriteria['sendEmail'] = $this->getSanitizer()->getCheckbox('sendEmail'); $filterCriteria['nonusers'] = $this->getSanitizer()->getString('nonusers'); // Return return [ 'filterCriteria' => json_encode($filterCriteria), 'schedule' => $schedule ]; } /** @inheritdoc */ public function generateSavedReportName($filterCriteria) { if ($filterCriteria['type'] == 'layout') { try { $layout = $this->layoutFactory->getById($filterCriteria['layoutId']); } catch (NotFoundException $error) { // Get the campaign ID $campaignId = $this->layoutFactory->getCampaignIdFromLayoutHistory($filterCriteria['layoutId']); $layoutId = $this->layoutFactory->getLatestLayoutIdFromLayoutHistory($campaignId); $layout = $this->layoutFactory->getById($layoutId); } $saveAs = __(ucfirst($filterCriteria['filter']). ' report for') . ' Layout '. $layout->layout; } else if ($filterCriteria['type'] == 'media') { try { $media = $this->mediaFactory->getById($filterCriteria['mediaId']); $saveAs = __(ucfirst($filterCriteria['filter']). ' report for') . ' Media '. $media->name; } catch (NotFoundException $error) { $saveAs = 'Media ' . __('Not Found'); } } else if ($filterCriteria['type'] == 'event') { $saveAs = __(ucfirst($filterCriteria['filter']). ' report for') . ' Event '. $filterCriteria['eventTag']; } else { $saveAs = __(ucfirst($filterCriteria['filter']). ' report for') . ' Type '. $filterCriteria['type']; } return $saveAs; } /** @inheritdoc */ public function getSavedReportResults($json, $savedReport) { // Return data to build chart return [ 'template' => 'summary-report-preview', 'chartData' => [ 'savedReport' => $savedReport, 'generatedOn' => $this->dateService->parse($savedReport->generatedOn, 'U')->format('Y-m-d H:i:s'), 'periodStart' => isset($json['periodStart']) ? $json['periodStart'] : '', 'periodEnd' => isset($json['periodEnd']) ? $json['periodEnd'] : '', 'labels' => json_encode($json['labels']), 'countData' => json_encode($json['countData']), 'durationData' => json_encode($json['durationData']), 'backgroundColor' => json_encode($json['backgroundColor']), 'borderColor' => json_encode($json['borderColor']), ] ]; } /** @inheritDoc */ public function getResults($filterCriteria) { $this->getLog()->debug('Filter criteria: '. json_encode($filterCriteria, JSON_PRETTY_PRINT)); $type = strtolower($this->getSanitizer()->getString('type', $filterCriteria)); $layoutId = $this->getSanitizer()->getInt('layoutId', $filterCriteria); $mediaId = $this->getSanitizer()->getInt('mediaId', $filterCriteria); $eventTag = $this->getSanitizer()->getString('eventTag', $filterCriteria); // Get an array of display id this user has access to. $displayIds = []; foreach ($this->displayFactory->query() as $display) { $displayIds[] = $display->displayId; } if (count($displayIds) <= 0) { throw new InvalidArgumentException(__('No displays with View permissions'), 'displays'); } // // From and To Date Selection // -------------------------- // Our report has a range filter which determins whether or not the user has to enter their own from / to dates // check the range filter first and set from/to dates accordingly. $reportFilter = $this->getSanitizer()->getString('reportFilter', $filterCriteria); // Use the current date as a helper $now = $this->getDate()->parse(); switch ($reportFilter) { case 'today': $fromDt = $now->copy()->startOfDay(); $toDt = $fromDt->copy()->addDay(); $groupByFilter = 'byhour'; break; case 'yesterday': $fromDt = $now->copy()->startOfDay()->subDay(); $toDt = $now->copy()->startOfDay(); $groupByFilter = 'byhour'; break; case 'thisweek': $fromDt = $now->copy()->startOfWeek(); $toDt = $fromDt->copy()->addWeek(); $groupByFilter = 'byday'; break; case 'thismonth': $fromDt = $now->copy()->startOfMonth(); $toDt = $fromDt->copy()->addMonth(); // User can pick their own group by filter when they provide a manual range $groupByFilter = $this->getSanitizer()->getString('groupByFilter', $filterCriteria); break; case 'thisyear': $fromDt = $now->copy()->startOfYear(); $toDt = $fromDt->copy()->addYear(); // User can pick their own group by filter when they provide a manual range $groupByFilter = $this->getSanitizer()->getString('groupByFilter', $filterCriteria); break; case 'lastweek': $fromDt = $now->copy()->startOfWeek()->subWeek(); $toDt = $fromDt->copy()->addWeek(); $groupByFilter = 'byday'; break; case 'lastmonth': $fromDt = $now->copy()->startOfMonth()->subMonth(); $toDt = $fromDt->copy()->addMonth(); // User can pick their own group by filter when they provide a manual range $groupByFilter = $this->getSanitizer()->getString('groupByFilter', $filterCriteria); break; case 'lastyear': $fromDt = $now->copy()->startOfYear()->subYear(); $toDt = $fromDt->copy()->addYear(); // User can pick their own group by filter when they provide a manual range $groupByFilter = $this->getSanitizer()->getString('groupByFilter', $filterCriteria); break; case '': default: // Expect dates to be provided. $fromDt = $this->getSanitizer()->getDate('statsFromDt', $this->getDate()->parse()->addDay(-1)); $fromDt->startOfDay(); $toDt = $this->getSanitizer()->getDate('statsToDt', $this->getDate()->parse()); $toDt->addDay()->startOfDay(); // What if the fromdt and todt are exactly the same? // in this case assume an entire day from midnight on the fromdt to midnight on the todt (i.e. add a day to the todt) if ($fromDt == $toDt) { $toDt->addDay(); } // User can pick their own group by filter when they provide a manual range $groupByFilter = $this->getSanitizer()->getString('groupByFilter', $filterCriteria); break; } // // Get Results! // ------------- $timeSeriesStore = $this->getTimeSeriesStore()->getEngine(); $this->getLog()->debug('Timeseries store is ' . $timeSeriesStore); if ($timeSeriesStore == 'mongodb') { $result = $this->getSummaryReportMongoDb($fromDt, $toDt, $groupByFilter, $displayIds, $type, $layoutId, $mediaId, $eventTag, $reportFilter); } else { $result = $this->getSummaryReportMySql($fromDt, $toDt, $groupByFilter, $displayIds, $type, $layoutId, $mediaId, $eventTag); } // // Output Results // -------------- $labels = []; $countData = []; $durationData = []; $backgroundColor = []; $borderColor = []; // Summary report result in chart if (count($result) > 0) { foreach ($result['result'] as $row) { // Label $labels[] = $row['label']; $backgroundColor[] = 'rgb(95, 186, 218, 0.6)'; $borderColor[] = 'rgb(240,93,41, 0.8)'; $count = $this->getSanitizer()->int($row['NumberPlays']); $countData[] = ($count == '') ? 0 : $count; $duration = $this->getSanitizer()->int($row['Duration']); $durationData[] = ($duration == '') ? 0 : $duration; } } // Return data to build chart return [ 'periodStart' => $this->getDate()->getLocalDate($fromDt), 'periodEnd' => $this->getDate()->getLocalDate($toDt), 'labels' => $labels, 'countData' => $countData, 'durationData' => $durationData, 'backgroundColor' => $backgroundColor, 'borderColor' => $borderColor, ]; } /** * MySQL summary report * @param \Jenssegers\Date\Date $fromDt The filter range from date * @param \Jenssegers\Date\Date $toDt The filter range to date * @param string $groupByFilter Grouping, byhour, byday, byweek, bymonth * @param $displayIds * @param $type * @param $layoutId * @param $mediaId * @param $eventTag * @return array */ private function getSummaryReportMySql($fromDt, $toDt, $groupByFilter, $displayIds, $type, $layoutId, $mediaId, $eventTag) { // Only return something if we have the necessary options selected. if ( (($type == 'media') && ($mediaId != '')) || (($type == 'layout') && ($layoutId != '')) || (($type == 'event') && ($eventTag != '')) ) { // Create periods covering the from/to dates // ----------------------------------------- try { $periods = $this->getTemporaryPeriodsTable($fromDt, $toDt, $groupByFilter); } catch (InvalidArgumentException $invalidArgumentException) { return []; } // Join in stats // ------------- $select = ' SELECT start, end, periodsWithStats.id, MAX(periodsWithStats.label) AS label, SUM(count) as NumberPlays, CONVERT(SUM(periodsWithStats.actualDiff), SIGNED INTEGER) as Duration FROM ( SELECT *, GREATEST(periods.start, statStart, :fromDt) AS actualStart, LEAST(periods.end, statEnd, :toDt) AS actualEnd, LEAST(stat.duration, LEAST(periods.end, statEnd, :toDt) - GREATEST(periods.start, statStart, :fromDt)) AS actualDiff FROM `' . $periods . '` AS periods LEFT OUTER JOIN ( SELECT layout.Layout, IFNULL(`media`.name, IFNULL(`widgetoption`.value, `widget`.type)) AS Media, stat.mediaId, stat.`start` as statStart, stat.`end` as statEnd, stat.duration, stat.`count` FROM stat LEFT OUTER JOIN layout ON layout.layoutID = stat.layoutID LEFT OUTER JOIN `widget` ON `widget`.widgetId = stat.widgetId LEFT OUTER JOIN `widgetoption` ON `widgetoption`.widgetId = `widget`.widgetId AND `widgetoption`.type = \'attrib\' AND `widgetoption`.option = \'name\' LEFT OUTER JOIN `media` ON `media`.mediaId = `stat`.mediaId WHERE stat.type <> \'displaydown\' AND stat.start < :toDt AND stat.end >= :fromDt '; $params = [ 'fromDt' => $fromDt->format('U'), 'toDt' => $toDt->format('U') ]; // Displays if (count($displayIds) > 0) { $select .= ' AND stat.displayID IN (' . implode(',', $displayIds) . ') '; } // Type filter if (($type == 'layout') && ($layoutId != '')) { // Filter by Layout $select .= ' AND `stat`.type = \'layout\' AND `stat`.campaignId = (SELECT campaignId FROM layouthistory WHERE layoutId = :layoutId) '; $params['layoutId'] = $layoutId; } elseif (($type == 'media') && ($mediaId != '')) { // Filter by Media $select .= ' AND `stat`.type = \'media\' AND IFNULL(`media`.mediaId, 0) <> 0 AND `stat`.mediaId = :mediaId '; $params['mediaId'] = $mediaId; } elseif (($type == 'event') && ($eventTag != '')) { // Filter by Event $select .= ' AND `stat`.type = \'event\' AND `stat`.tag = :tag '; $params['tag'] = $eventTag; } $select .= ' ) stat ON statStart < periods.`end` AND statEnd > periods.`start` '; // Periods and Stats tables are joined, we should only have periods we're interested in, but it // wont hurt to restrict them $select .= ' WHERE periods.`start` < :toDt AND periods.`end` > :fromDt '; // Close out our containing view and group things together $select .= ' ) periodsWithStats GROUP BY periodsWithStats.id ORDER BY periodsWithStats.id '; return [ 'result' => $this->getStore()->select($select, $params), 'periodStart' => $fromDt->format('Y-m-d H:i:s'), 'periodEnd' => $toDt->format('Y-m-d H:i:s') ]; } else { return []; } } /** * MongoDB summary report * @param \Jenssegers\Date\Date $fromDt The filter range from date * @param \Jenssegers\Date\Date $toDt The filter range to date * @param string $groupByFilter Grouping, byhour, byday, byweek, bymonth * @param $displayIds * @param $type * @param $layoutId * @param $mediaId * @param $eventTag * @param $reportFilter * @return array */ private function getSummaryReportMongoDb($fromDt, $toDt, $groupByFilter, $displayIds, $type, $layoutId, $mediaId, $eventTag, $reportFilter) { if ( (($type == 'media') && ($mediaId != '')) || (($type == 'layout') && ($layoutId != '')) || (($type == 'event') && ($eventTag != '')) ) { $diffInDays = $toDt->diffInDays($fromDt); if ($groupByFilter == 'byhour') { $hour = 1; $input = range(0, 23); } elseif ($groupByFilter == 'byday') { $hour = 24; $input = range(0, $diffInDays - 1); } elseif ($groupByFilter == 'byweek') { $hour = 24 * 7; $input = range(0, ceil($diffInDays / 7)); } elseif ($groupByFilter == 'bymonth') { $hour = 24; $input = range(0, ceil($diffInDays / 30)); } else { $this->getLog()->error('Unknown Grouping Selected ' . $groupByFilter); throw new InvalidArgumentException('Unknown Grouping ' . $groupByFilter, 'groupByFilter'); } $filterRangeStart = new UTCDateTime($fromDt->format('U') * 1000); $filterRangeEnd = new UTCDateTime($toDt->format('U') * 1000); // Extend the range if (($groupByFilter == 'byhour') || ($groupByFilter == 'byday')) { $extendedPeriodStart = $filterRangeStart; $extendedPeriodEnd = $filterRangeEnd; } elseif ($groupByFilter == 'byweek') { // Extend upto the start of the first week of the fromdt, and end of the week of the todt $startOfWeek = $fromDt->copy()->startOfWeek(); $endOfWeek = $toDt->copy()->endOfWeek()->addSecond(); $extendedPeriodStart = new UTCDateTime( $startOfWeek->format('U') * 1000); $extendedPeriodEnd = new UTCDateTime($endOfWeek->format('U') * 1000); } elseif ($groupByFilter == 'bymonth') { if ($reportFilter == '') { // We extend the fromDt and toDt range filter // so that we can generate each month period $fromDtStartOfMonth = $fromDt->copy()->startOfMonth(); $toDtEndOfMonth = $toDt->copy()->endOfMonth()->addSecond(); // Generate all months that lie in the extended range $monthperiods = []; foreach ($input as $key => $value) { $monthPeriodStart = $fromDtStartOfMonth->copy()->addMonth($key); $monthPeriodEnd = $fromDtStartOfMonth->copy()->addMonth($key)->addMonth(); // Remove the month period which crossed the extended end range if ($monthPeriodStart >= $toDtEndOfMonth) { continue; } $monthperiods[$key]['start'] = new UTCDateTime( $monthPeriodStart->format('U') * 1000); $monthperiods[$key]['end'] = new UTCDateTime( $monthPeriodEnd->format('U') * 1000); } $extendedPeriodStart = new UTCDateTime( $fromDtStartOfMonth->format('U') * 1000); $extendedPeriodEnd = new UTCDateTime( $toDtEndOfMonth->format('U') * 1000); } elseif (($reportFilter == 'thisyear') || ($reportFilter == 'lastyear')) { $extendedPeriodStart = $filterRangeStart; $extendedPeriodEnd = $filterRangeEnd; $start = $fromDt->copy()->subMonth()->startOfMonth(); $end = $fromDt->copy()->startOfMonth(); // Generate all 12 months $monthperiods = []; foreach ($input as $key => $value) { $monthperiods[$key]['start'] = new UTCDateTime( $start->addMonth()->format('U') * 1000); $monthperiods[$key]['end'] = new UTCDateTime( $end->addMonth()->format('U') * 1000); } } } $this->getLog()->debug('Period start: '.$filterRangeStart->toDateTime()->format('Y-m-d H:i:s'). ' Period end: '. $filterRangeEnd->toDateTime()->format('Y-m-d H:i:s')); // Type filter if (($type == 'layout') && ($layoutId != '')) { // Get the campaign ID $campaignId = $this->layoutFactory->getCampaignIdFromLayoutHistory($layoutId); $matchType = [ '$eq' => [ '$type', 'layout' ] ]; $matchId = [ '$eq' => [ '$campaignId', $campaignId ] ]; } elseif (($type == 'media') && ($mediaId != '')) { $matchType = [ '$eq' => [ '$type', 'media' ] ]; $matchId = [ '$eq' => [ '$mediaId', $mediaId ] ]; } elseif (($type == 'event') && ($eventTag != '')) { $matchType = [ '$eq' => [ '$type', 'event' ] ]; $matchId = [ '$eq' => [ '$eventName', $eventTag ] ]; } if ($groupByFilter == 'byweek') { // PERIOD GENERATION // Addition of 7 days from start $projectMap = [ '$project' => [ 'periods' => [ '$map' => [ 'input' => $input, 'as' => 'number', 'in' => [ 'start' => [ '$add' => [ $extendedPeriodStart, [ '$multiply' => [ '$$number', $hour * 3600000 ] ] ] ], 'end' => [ '$add' => [ [ '$add' => [ $extendedPeriodStart, $hour * 3600000 ] ], [ '$multiply' => [ '$$number', $hour * 3600000 ] ] ] ], ] ] ] ] ]; } elseif ($groupByFilter == 'bymonth') { $projectMap = [ '$project' => [ 'periods' => [ '$map' => [ 'input' => $monthperiods, 'as' => 'number', 'in' => [ 'start' => '$$number.start', 'end' => '$$number.end', ] ] ] ] ]; } else { // PERIOD GENERATION // Addition of 1 day/hour from start $projectMap = [ '$project' => [ 'periods' => [ '$map' => [ 'input' => $input, 'as' => 'number', 'in' => [ 'start' => [ '$add' => [ $extendedPeriodStart, [ '$multiply' => [ $hour * 3600000, '$$number' ] ] ] ], 'end' => [ '$add' => [ [ '$add' => [ $extendedPeriodStart, [ '$multiply' => [ $hour * 3600000, '$$number' ] ] ] ] , $hour * 3600000 ] ], ] ] ] ] ]; } // GROUP BY $groupBy = [ 'period_start' => '$period_start', 'period_end' => '$period_end' ]; // PERIODS QUERY $cursorPeriodQuery = [ $projectMap, // periods needs to be unwind to merge next [ '$unwind' => '$periods' ], // replace the root to eliminate _id and get only periods [ '$replaceRoot' => [ 'newRoot' => '$periods' ] ], [ '$project' => [ 'start' => 1, 'end' => 1, ] ], [ '$match' => [ 'start' => [ '$lt' => $extendedPeriodEnd ], 'end' => [ '$gt' => $extendedPeriodStart ] ] ], ]; // Periods result $periods = $this->getTimeSeriesStore()->executeQuery(['collection' => $this->periodTable, 'query' => $cursorPeriodQuery]); // STAT AGGREGATION QUERY $statQuery = [ [ '$match' => [ 'start' => [ '$lt' => $filterRangeEnd ], 'end' => [ '$gt' => $filterRangeStart ], ] ], [ '$lookup' => [ 'from' => 'period', 'let' => [ 'stat_start' => '$start', 'stat_end' => '$end', 'stat_duration' => '$duration', 'stat_count' => '$count', ], 'pipeline' => [ $projectMap, [ '$unwind' => '$periods' ], ], 'as' => 'statdata' ] ], [ '$unwind' => '$statdata' ], [ '$match' => [ '$expr' => [ '$and' => [ // match media id / layout id $matchType, $matchId, // display ids [ '$in' => [ '$displayId', $displayIds ] ], // stat.start < period end AND stat.end > period start // for example, when report filter 'today' is selected // where start is less than last hour of the day + 1 hour (i.e., nextday of today) // and end is greater than or equal first hour of the day [ '$lt' => [ '$start', '$statdata.periods.end' ] ], [ '$gt' => [ '$end', '$statdata.periods.start' ] ], ] ] ] ], [ '$project' => [ '_id' => 1, 'count' => 1, 'duration' => 1, 'start' => 1, 'end' => 1, 'period_start' => '$statdata.periods.start', 'period_end' => '$statdata.periods.end', 'monthNo' => [ '$month' => '$statdata.periods.start' ], 'yearDate' => [ '$isoWeekYear' => '$statdata.periods.start' ], 'weekNo' => [ '$isoWeek' => '$statdata.periods.start' ], 'actualStart' => [ '$max' => [ '$start', '$statdata.periods.start', $filterRangeStart ] ], 'actualEnd' => [ '$min' => [ '$end', '$statdata.periods.end', $filterRangeEnd ] ], 'actualDiff' => [ '$min' => [ '$duration', [ '$divide' => [ [ '$subtract' => [ ['$min' => [ '$end', '$statdata.periods.end', $filterRangeEnd ]], ['$max' => [ '$start', '$statdata.periods.start', $filterRangeStart ]] ] ], 1000 ] ] ] ], ] ], [ '$group' => [ '_id' => $groupBy, 'period_start' => ['$first' => '$period_start'], 'period_end' => ['$first' => '$period_end'], 'NumberPlays' => ['$sum' => '$count'], 'Duration' => ['$sum' => '$actualDiff'], 'start' => ['$first' => '$start'], 'end' => ['$first' => '$end'], ] ], [ '$project' => [ 'start' => '$start', 'end' => '$end', 'period_start' => 1, 'period_end' => 1, 'NumberPlays' => 1, 'Duration' => 1, ] ], ]; // Stats result $results = $this->getTimeSeriesStore()->executeQuery(['collection' => $this->table, 'query' => $statQuery]); // Run period loop and map the stat result for each period $resultArray = []; foreach ($periods as $key => $period) { // UTC date format $period_start_u = $period['start']->toDateTime()->format('U'); $period_end_u = $period['end']->toDateTime()->format('U'); // CMS date $period_start = $this->getDate()->parse($period_start_u, 'U'); $period_end = $this->getDate()->parse($period_end_u, 'U'); if ($groupByFilter == 'byhour'){ $label = $period_start->format('g:i A'); } elseif ($groupByFilter == 'byday') { if ( ($reportFilter == 'thisweek') || ($reportFilter == 'lastweek') ) { $label = $period_start->format('D'); } else { $label = $period_start->format('Y-m-d'); } } elseif ($groupByFilter == 'byweek') { $weekstart = $period_start->format('M d'); $weekend = $period_end->format('M d'); $weekno = $period_start->format('W'); if ($period_start_u < $fromDt->copy()->format('U')) { $weekstart = $fromDt->copy()->format('M-d'); } if ($period_end_u > $toDt->copy()->format('U')) { $weekend = $toDt->copy()->format('M-d'); } $label = $weekstart . ' - ' . $weekend . ' (w' . $weekno . ')'; } elseif ($groupByFilter == 'bymonth') { $label = $period_start->format('M'); if ($reportFilter == '') { $label .= ' ' .$period_start->format('Y'); } } else { $label = 'N/A'; } $matched = false; foreach ($results as $k => $result) { if( $result['period_start'] == $period['start'] ) { $NumberPlays = $result['NumberPlays']; $Duration = $result['Duration']; $matched = true; break; } } // Chart label $resultArray[$key]['label'] = $label; if($matched == true) { $resultArray[$key]['NumberPlays'] = $NumberPlays; $resultArray[$key]['Duration'] = $Duration; } else { $resultArray[$key]['NumberPlays'] = 0; $resultArray[$key]['Duration'] = 0; } } return [ 'result' => $resultArray, 'periodStart' => $fromDt->format('Y-m-d H:i:s'), 'periodEnd' => $toDt->format('Y-m-d H:i:s') ]; } else { return []; } } } ReportInterface.php 0000644 00000004254 14716415152 0010364 0 ustar 00 . */ namespace Xibo\Report; /** * Interface ReportInterface * @package Xibo\Report */ interface ReportInterface { /** * Set factories * @param \Slim\Helper\Set $container * @return $this */ public function setFactories($container); /** * Return the twig file name of the report form * Load the report form * @return string */ public function getReportForm(); /** * Return the twig file name of the report email template * @return string */ public function getReportEmailTemplate(); /** * Get chart script * @return string */ public function getReportChartScript($results); /** * Populate form title and hidden fields * @return array */ public function getReportScheduleFormData(); /** * Set Report Schedule form data * @return array */ public function setReportScheduleFormData(); /** * Generate saved report name * @param $filterCriteria * @return string */ public function generateSavedReportName($filterCriteria); /** * Return data to build chart of saved report * @param array $json * @param object savedReport * @return array */ public function getSavedReportResults($json, $savedReport); /** * Return results * @param $filterCriteria * @return array */ public function getResults($filterCriteria); } ReportTrait.php 0000644 00000032246 14716415152 0007551 0 ustar 00 . */ namespace Xibo\Report; use Slim\Http\Request; use Xibo\Exception\InvalidArgumentException; use Xibo\Service\ConfigServiceInterface; use Xibo\Service\DateServiceInterface; use Xibo\Service\LogServiceInterface; use Xibo\Service\SanitizerServiceInterface; use Xibo\Storage\StorageServiceInterface; use Xibo\Storage\TimeSeriesStoreInterface; trait ReportTrait { /** * @var \Xibo\Helper\ApplicationState */ private $state; /** * @var StorageServiceInterface */ private $store; /** * @var TimeSeriesStoreInterface */ private $timeSeriesStore; /** * @var LogServiceInterface */ private $logService; /** * @var ConfigServiceInterface */ private $configService; /** * @var DateServiceInterface */ private $dateService; /** * @var SanitizerServiceInterface */ private $sanitizerService; /** * @var Request */ private $request; private $userId; /** * Set common dependencies. * @param \Xibo\Helper\ApplicationState $state * @param StorageServiceInterface $store * @param TimeSeriesStoreInterface $timeSeriesStore * @param LogServiceInterface $log * @param ConfigServiceInterface $config * @param DateServiceInterface $date * @param SanitizerServiceInterface $sanitizer * @return $this */ public function setCommonDependencies($state, $store, $timeSeriesStore, $log, $config, $date, $sanitizer) { $this->state = $state; $this->store = $store; $this->timeSeriesStore = $timeSeriesStore; $this->logService = $log; $this->configService = $config; $this->dateService = $date; $this->sanitizerService = $sanitizer; return $this; } /** * Get the Application State * @return \Xibo\Helper\ApplicationState */ protected function getState() { return $this->state; } /** * Get Store * @return StorageServiceInterface */ protected function getStore() { return $this->store; } /** * Get TimeSeriesStore * @return TimeSeriesStoreInterface */ protected function getTimeSeriesStore() { return $this->timeSeriesStore; } /** * Get Log * @return LogServiceInterface */ protected function getLog() { return $this->logService; } /** * Get Config * @return ConfigServiceInterface */ public function getConfig() { return $this->configService; } /** * Get Date * @return DateServiceInterface */ protected function getDate() { return $this->dateService; } /** * Get Sanitizer * @return SanitizerServiceInterface */ protected function getSanitizer() { return $this->sanitizerService; } /** * Get Request * @return Request */ private function getRequest() { if ($this->request == null) throw new \RuntimeException('....... called before Request has been set'); return $this->request; } public function generateHourPeriods($filterRangeStart, $filterRangeEnd, $start,$end, $ranges) { $periodData = []; // to generate periods table // Generate all hours of the period foreach ($ranges as $range) { $startHour = $start->addHour()->format('U'); // Remove the period which crossed the end range if ($startHour >= $filterRangeEnd) { continue; } // Period start $periodData[$range]['start'] = $startHour; if ($periodData[$range]['start'] < $filterRangeStart) { $periodData[$range]['start'] = $filterRangeStart; } // Period end $periodData[$range]['end'] = $end->addHour()->format('U'); if ($periodData[$range]['end'] > $filterRangeEnd) { $periodData[$range]['end'] = $filterRangeEnd; } $hourofday = $this->dateService->parse($periodData[$range]['start'], 'U')->hour; // groupbycol = hour $periodData[$range]['groupbycol'] = $hourofday; } return $periodData; } public function generateDayPeriods($filterRangeStart, $filterRangeEnd, $start, $end, $ranges, $groupByFilter = null) { $periodData = []; // to generate periods table // Generate all days of the period foreach ($ranges as $range) { $startDay = $start->addDay()->format('U'); // Remove the period which crossed the end range if ($startDay >= $filterRangeEnd) { continue; } // Period start $periodData[$range]['start'] = $startDay; if ($periodData[$range]['start'] < $filterRangeStart) { $periodData[$range]['start'] = $filterRangeStart; } // Period end $periodData[$range]['end'] = $end->addDay()->format('U'); if ($periodData[$range]['end'] > $filterRangeEnd) { $periodData[$range]['end'] = $filterRangeEnd; } if ($groupByFilter == 'bydayofweek') { $groupbycol = $this->dateService->parse($periodData[$range]['start'], 'U')->dayOfWeekIso; } else { $groupbycol = $this->dateService->parse($periodData[$range]['start'], 'U')->day; } // groupbycol = dayofweek $periodData[$range]['groupbycol'] = $groupbycol; } return $periodData; } /** * Get a temporary table representing the periods covered * @param \Jenssegers\Date\Date $fromDt * @param \Jenssegers\Date\Date $toDt * @param string $groupByFilter * @param string $table * @param string $customLabel Custom Label * @return string * @throws \Xibo\Exception\InvalidArgumentException */ public function getTemporaryPeriodsTable($fromDt, $toDt, $groupByFilter, $table = 'temp_periods', $customLabel = 'Y-m-d H:i:s') { // My from/to dt represent the entire range we're interested in. // we need to generate periods according to our grouping, within that range. // Clone them so as to not effect the calling object $fromDt = $fromDt->copy(); $toDt = $toDt->copy(); // our from/to dates might not sit nicely inside our period groupings // for example if we look at June, by week, the 1st of June is a Saturday, week 22. // NB: // FromDT/ToDt should always be at the start of the day. switch ($groupByFilter) { case 'byweek': $fromDt->startOfWeek(); break; case 'bymonth': $fromDt->startOfMonth(); break; } // Temporary Periods Table // ----------------------- // we will use a temporary table for this. // Drop table if exists $this->getStore()->getConnection()->exec(' DROP TABLE IF EXISTS `' . $table . '`'); $this->getStore()->getConnection()->exec(' CREATE TEMPORARY TABLE `' . $table . '` ( id INT, customLabel VARCHAR(20), label VARCHAR(20), start INT, end INT ); '); // Prepare an insert statement $periods = $this->getStore()->getConnection()->prepare(' INSERT INTO `' . $table . '` (id, customLabel, label, start, end) VALUES (:id, :customLabel, :label, :start, :end) '); // Loop until we've covered all periods needed $loopDate = $fromDt->copy(); while ($toDt > $loopDate) { // We add different periods for each type of grouping if ($groupByFilter == 'byhour') { $periods->execute([ 'id' => $loopDate->hour, 'customLabel' => $loopDate->format($customLabel), 'label' => $loopDate->format('g:i A'), 'start' => $loopDate->format('U'), 'end' => $loopDate->addHour()->format('U') ]); } else if ($groupByFilter == 'byday') { $periods->execute([ 'id' => $loopDate->year . $loopDate->month . $loopDate->day, 'customLabel' => $loopDate->format($customLabel), 'label' => $loopDate->format('Y-m-d'), 'start' => $loopDate->format('U'), 'end' => $loopDate->addDay()->format('U') ]); } else if ($groupByFilter == 'byweek') { $periods->execute([ 'id' => $loopDate->weekOfYear . $loopDate->year, 'customLabel' => $loopDate->format($customLabel), 'label' => $loopDate->format('Y-m-d (\wW)'), 'start' => $loopDate->format('U'), 'end' => $loopDate->addWeek()->format('U') ]); } else if ($groupByFilter == 'bymonth') { $periods->execute([ 'id' => $loopDate->year . $loopDate->month, 'customLabel' => $loopDate->format($customLabel), 'label' => $loopDate->format('M'), 'start' => $loopDate->format('U'), 'end' => $loopDate->addMonth()->format('U') ]); } else if ($groupByFilter == 'bydayofweek') { $periods->execute([ 'id' => $loopDate->dayOfWeek, 'customLabel' => $loopDate->format($customLabel), 'label' => $loopDate->format('D'), 'start' => $loopDate->format('U'), 'end' => $loopDate->addDay()->format('U') ]); } else if ($groupByFilter == 'bydayofmonth') { $periods->execute([ 'id' => $loopDate->day, 'customLabel' => $loopDate->format($customLabel), 'label' => $loopDate->format('d'), 'start' => $loopDate->format('U'), 'end' => $loopDate->addDay()->format('U') ]); } else { $this->getLog()->error('Unknown Grouping Selected ' . $groupByFilter); throw new InvalidArgumentException('Unknown Grouping ' . $groupByFilter, 'groupByFilter'); } } $this->getLog()->debug(json_encode($this->store->select('SELECT * FROM ' . $table, []), JSON_PRETTY_PRINT)); return $table; } public function getUserId() { return $this->userId; } public function setUserId($userId) { $this->userId = $userId; return; } /** * Set the filter * @param array[Optional] $extraFilter * @return array */ public function gridRenderFilter($extraFilter = []) { // Handle filtering $filter = [ 'start' => $this->getSanitizer()->getInt('start', 0), 'length' => $this->getSanitizer()->getInt('length', 10) ]; $search = $this->getSanitizer()->getStringArray('search'); if (is_array($search) && isset($search['value'])) { $filter['search'] = $search['value']; } else if ($search != '') { $filter['search'] = $search; } // Merge with any extra filter items that have been provided $filter = array_merge($extraFilter, $filter); return $filter; } /** * Set the sort order * @return array */ public function gridRenderSort() { $columns = $this->getSanitizer()->getParam('columns', null); if ($columns === null || !is_array($columns) || count($columns) <= 0) { return null; } $order = $this->getSanitizer()->getParam('order', null); if ($order === null || !is_array($order) || count($order) <= 0) { return null; } return array_map(function ($element) use ($columns) { return ((isset($columns[$element['column']]['name']) && $columns[$element['column']]['name'] != '') ? '`' . $columns[$element['column']]['name'] . '`' : '`' . $columns[$element['column']]['data'] . '`') . (($element['dir'] == 'desc') ? ' DESC' : ''); }, $order); } } ProofOfPlay.php 0000644 00000120075 14716415152 0007470 0 ustar 00 'Display group', 'media' => 'Media', 'layout' => 'Layout' ]; /** * Report Constructor. * @param \Xibo\Helper\ApplicationState $state * @param StorageServiceInterface $store * @param TimeSeriesStoreInterface $timeSeriesStore * @param LogServiceInterface $log * @param ConfigServiceInterface $config * @param DateServiceInterface $date * @param SanitizerServiceInterface $sanitizer */ public function __construct($state, $store, $timeSeriesStore, $log, $config, $date, $sanitizer) { $this->setCommonDependencies($state, $store, $timeSeriesStore, $log, $config, $date, $sanitizer); } /** @inheritdoc */ public function setFactories($container) { $this->displayFactory = $container->get('displayFactory'); $this->mediaFactory = $container->get('mediaFactory'); $this->layoutFactory = $container->get('layoutFactory'); $this->savedReportFactory = $container->get('savedReportFactory'); $this->reportScheduleFactory = $container->get('reportScheduleFactory'); $this->userFactory = $container->get('userFactory'); $this->displayGroupFactory = $container->get('displayGroupFactory'); $this->reportService = $container->get('reportService'); return $this; } /** @inheritdoc */ public function getReportChartScript($results) { return null; } /** @inheritdoc */ public function getReportEmailTemplate() { return 'proofofplay-email-template.twig'; } /** @inheritdoc */ public function getReportForm() { return [ 'template' => 'proofofplay-report-form', 'data' => [ 'fromDate' => $this->getDate()->getLocalDate(time() - (86400 * 35)), 'fromDateOneDay' => $this->getDate()->getLocalDate(time() - 86400), 'toDate' => $this->getDate()->getLocalDate(), 'availableReports' => $this->reportService->listReports() ] ]; } /** @inheritdoc */ public function getReportScheduleFormData() { $data = []; $title = 'Add Report Schedule'; $data['formTitle'] = $title; $data['type'] = $this->getSanitizer()->getParam('type', ''); $data['tagsType'] = $this->getSanitizer()->getParam('tagsType', ''); $exactTags = $this->getSanitizer()->getParam('exactTags', false); $data['exactTags'] = ($exactTags == 'true') ? true : false; $tags = $this->getSanitizer()->getParam('tags', ''); $data['tags'] = $tags; $data['hiddenFields'] = ''; $data['reportName'] = 'proofofplayReport'; return [ 'template' => 'proofofplay-schedule-form-add', 'data' => $data ]; } /** @inheritdoc */ public function setReportScheduleFormData() { // We use the following variables in temp array $filter = $this->getSanitizer()->getString('filter'); $displayId = $this->getSanitizer()->getInt('displayId'); $layoutIds = $this->getSanitizer()->getIntArray('layoutId'); $mediaIds = $this->getSanitizer()->getIntArray('mediaId'); $type = $this->getSanitizer()->getString('type'); $sortBy = $this->getSanitizer()->getString('sortBy'); $tagsType = $this->getSanitizer()->getString('tagsType'); $tags = $this->getSanitizer()->getString('tags'); $exactTags = $this->getSanitizer()->getCheckbox('exactTags'); $temp = ['filter', 'displayId', 'layoutIds', 'mediaIds', 'type', 'sortBy', 'tagsType', 'tags', 'exactTags']; $filterCriteria = []; foreach ($temp as $value) { $filterCriteria[$value] = $$value; } $schedule = ''; if ($filter == 'daily') { $schedule = ReportSchedule::$SCHEDULE_DAILY; $filterCriteria['reportFilter'] = 'yesterday'; } else if ($filter == 'weekly') { $schedule = ReportSchedule::$SCHEDULE_WEEKLY; $filterCriteria['reportFilter'] = 'lastweek'; } else if ($filter == 'monthly') { $schedule = ReportSchedule::$SCHEDULE_MONTHLY; $filterCriteria['reportFilter'] = 'lastmonth'; } else if ($filter == 'yearly') { $schedule = ReportSchedule::$SCHEDULE_YEARLY; $filterCriteria['reportFilter'] = 'lastyear'; } $filterCriteria['sendEmail'] = $this->getSanitizer()->getCheckbox('sendEmail'); $filterCriteria['nonusers'] = $this->getSanitizer()->getString('nonusers'); // Return return [ 'filterCriteria' => json_encode($filterCriteria), 'schedule' => $schedule ]; } /** @inheritdoc */ public function generateSavedReportName($filterCriteria) { $saveAs = __(ucfirst($filterCriteria['filter']). ' report for Type') .': '; switch ($filterCriteria['type']) { case 'layout': $saveAs .= 'Layout. '; break; case 'media': $saveAs .= 'Media. '; break; case 'widget': $saveAs .= 'Widget. '; break; case 'event': $saveAs .= 'Event. '; break; default: $saveAs .= 'All. '; break; } if (count($filterCriteria['layoutIds']) > 0) { $layouts = ''; foreach ($filterCriteria['layoutIds'] as $id) { try { $layout = $this->layoutFactory->getById($id); } catch (NotFoundException $error) { // Get the campaign ID $campaignId = $this->layoutFactory->getCampaignIdFromLayoutHistory($id); $layoutId = $this->layoutFactory->getLatestLayoutIdFromLayoutHistory($campaignId); $layout = $this->layoutFactory->getById($layoutId); } $layouts .= $layout->layout . ', '; } $saveAs .= 'Layouts: '. $layouts; } if (count($filterCriteria['mediaIds']) > 0) { $medias = ''; foreach ($filterCriteria['mediaIds'] as $id) { try { $media = $this->mediaFactory->getById($id); $name = $media->name; } catch (NotFoundException $error) { $name = 'Media ' . __('Not Found'); } $medias .= $name . ', '; } $saveAs .= 'Media: ' . $medias; } if (!empty($filterCriteria['displayId'])) { // Get display try{ $displayName = $this->displayFactory->getById($filterCriteria['displayId'])->display; $saveAs .= '(Display: '. $displayName . ')'; } catch (NotFoundException $error){ $saveAs .= ' (DisplayId: ' . __('Not Found') . ' )'; } } return $saveAs; } /** @inheritdoc */ public function getSavedReportResults($json, $savedReport) { // Get filter criteria $rs = $this->reportScheduleFactory->getById($savedReport->reportScheduleId)->filterCriteria; $filterCriteria = json_decode($rs, true); $tagsType = $filterCriteria['tagsType']; $tags = $filterCriteria['tags']; $exactTags = ($filterCriteria['exactTags'] == 1) ? ' (exact match)': ''; // Show filter criteria $filterInfo = ''; if ($tags != null) { $filterInfo = __('Tags from') . ': '. $this->tagsType[$tagsType]. ', Tags: '. $tags. $exactTags; } // Return data to build chart return [ 'template' => 'proofofplay-report-preview', 'chartData' => [ 'savedReport' => $savedReport, 'filterInfo' => $filterInfo, 'generatedOn' => $this->dateService->parse($savedReport->generatedOn, 'U')->format('Y-m-d H:i:s'), 'periodStart' => isset($json['periodStart']) ? $json['periodStart'] : '', 'periodEnd' => isset($json['periodEnd']) ? $json['periodEnd'] : '', 'result' => json_encode($json['result']), ] ]; } /** @inheritdoc */ public function getResults($filterCriteria) { $displayId = $this->getSanitizer()->getInt('displayId', $filterCriteria); $layoutIds = $this->getSanitizer()->getIntArray('layoutId', $filterCriteria); $mediaIds = $this->getSanitizer()->getIntArray('mediaId', $filterCriteria); $type = strtolower($this->getSanitizer()->getString('type')); $tags = $this->getSanitizer()->getString('tags', $filterCriteria); $tagsType = $this->getSanitizer()->getString('tagsType', $filterCriteria); $exactTags = $this->getSanitizer()->getCheckbox('exactTags', $filterCriteria); // Do not filter by display if super admin and no display is selected // Super admin will be able to see stat records of deleted display, we will not filter by display later $displayIds = []; // Get user $userId = $this->getUserId(); if ($userId == null) { $user = $this->userFactory->getUser(); } else { $user = $this->userFactory->getById($userId); } $displayFactory = clone $this->displayFactory; $displayFactory->setAclDependencies($user, $this->userFactory); if ($user->userTypeId != 1) { // Get an array of display id this user has access to. foreach ($displayFactory->query() as $display) { $displayIds[] = $display->displayId; } if (count($displayIds) <= 0) throw new InvalidArgumentException(__('No displays with View permissions'), 'displays'); // Set displayIds as [-1] if the user selected a display for which they don't have permission if ($displayId != 0) { if (!in_array($displayId, $displayIds)) { $displayIds = [-1]; } else { $displayIds = [$displayId]; } } } else { if ($displayId != 0) { $displayIds = [$displayId]; } } // Sorting? if($filterCriteria == null) { $filterBy = $this->gridRenderFilter(); $sortOrder = $this->gridRenderSort(); $columns = []; if (is_array($sortOrder)) $columns = $sortOrder; // Paging $start = 0; $length = 0; if ($filterBy !== null && $this->getSanitizer()->getInt('start', $filterBy) !== null && $this->getSanitizer()->getInt('length', $filterBy) !== null) { $start = intval($this->getSanitizer()->getInt('start', $filterBy), 0); $length = $this->getSanitizer()->getInt('length', 10, $filterBy); } } else { $start = 0; $length = -1; $sortBy = $this->getSanitizer()->getString('sortBy', $filterCriteria); $columns = ($sortBy == '') ? ['widgetId'] : [$sortBy]; } // // From and To Date Selection // -------------------------- // Our report has a range filter which determins whether or not the user has to enter their own from / to dates // check the range filter first and set from/to dates accordingly. $reportFilter = $this->getSanitizer()->getString('reportFilter', $filterCriteria); // Use the current date as a helper $now = $this->getDate()->parse(); switch ($reportFilter) { case 'today': $fromDt = $now->copy()->startOfDay(); $toDt = $fromDt->copy()->addDay(); break; case 'yesterday': $fromDt = $now->copy()->startOfDay()->subDay(); $toDt = $now->copy()->startOfDay(); break; case 'thisweek': $fromDt = $now->copy()->startOfWeek(); $toDt = $fromDt->copy()->addWeek(); break; case 'thismonth': $fromDt = $now->copy()->startOfMonth(); $toDt = $fromDt->copy()->addMonth(); break; case 'thisyear': $fromDt = $now->copy()->startOfYear(); $toDt = $fromDt->copy()->addYear(); break; case 'lastweek': $fromDt = $now->copy()->startOfWeek()->subWeek(); $toDt = $fromDt->copy()->addWeek(); break; case 'lastmonth': $fromDt = $now->copy()->startOfMonth()->subMonth(); $toDt = $fromDt->copy()->addMonth(); break; case 'lastyear': $fromDt = $now->copy()->startOfYear()->subYear(); $toDt = $fromDt->copy()->addYear(); break; case '': default: // Expect dates to be provided. $fromDt = $this->getSanitizer()->getDate('statsFromDt', $this->getDate()->parse()->addDay(-1)); $fromDt->startOfDay(); $toDt = $this->getSanitizer()->getDate('statsToDt', $this->getDate()->parse()); $toDt->startOfDay(); $fromDtTime = $this->getSanitizer()->getString('statsFromDtTime'); $toDtTime = $this->getSanitizer()->getString('statsToDtTime'); if ($fromDtTime !== null && $toDtTime !== null) { $startTimeArray = explode(':', $fromDtTime); $fromDt->setTime(intval($startTimeArray[0]), intval($startTimeArray[1])); $toTimeArray = explode(':', $toDtTime); $toDt->setTime(intval($toTimeArray[0]), intval($toTimeArray[1])); } // What if the fromdt and todt are exactly the same? // in this case assume an entire day from midnight on the fromdt to midnight on the todt (i.e. add a day to the todt) if ($fromDt == $toDt) { $toDt->addDay(); } break; } // // Get Results! // ------------- $timeSeriesStore = $this->getTimeSeriesStore()->getEngine(); if ($timeSeriesStore == 'mongodb') { $result = $this->getProofOfPlayReportMongoDb($fromDt, $toDt, $displayIds, $layoutIds, $mediaIds, $type, $columns, $tags, $tagsType, $exactTags, $start, $length); } else { $result = $this->getProofOfPlayReportMySql($fromDt, $toDt, $displayIds, $layoutIds, $mediaIds, $type, $columns, $tags, $tagsType, $exactTags, $start, $length); } // Sanitize results $rows = []; foreach ($result['result'] as $row) { $entry = []; $widgetId = $this->getSanitizer()->int($row['widgetId']); $widgetName = $this->getSanitizer()->string($row['media']); // If the media name is empty, and the widgetid is not, then we can assume it has been deleted. $widgetName = ($widgetName == '' && $widgetId != 0) ? __('Deleted from Layout') : $widgetName; $displayName = $this->getSanitizer()->string($row['display']); $layoutName = $this->getSanitizer()->string($row['layout']); $entry['type'] = $this->getSanitizer()->string($row['type']); $entry['displayId'] = $this->getSanitizer()->int(($row['displayId'])); $entry['display'] = ($displayName != '') ? $displayName : __('Not Found'); $entry['layoutId'] = $this->getSanitizer()->int($row['layoutId']); $entry['layout'] = ($layoutName != '') ? $layoutName : __('Not Found'); $entry['widgetId'] = $this->getSanitizer()->int($row['widgetId']); $entry['media'] = $widgetName; $entry['tag'] = $this->getSanitizer()->string($row['tag']); $entry['numberPlays'] = $this->getSanitizer()->int($row['numberPlays']); $entry['duration'] = $this->getSanitizer()->int($row['duration']); $entry['minStart'] = $this->getDate()->parse($row['minStart'], 'U')->format('Y-m-d H:i:s'); $entry['maxEnd'] = $this->getDate()->parse($row['maxEnd'], 'U')->format('Y-m-d H:i:s'); $entry['mediaId'] = $this->getSanitizer()->int($row['mediaId']); $rows[] = $entry; } // Paging if ($result['count'] > 0) { $this->getState()->recordsTotal = intval($result['totalStats']); } // // Output Results // -------------- $this->getState()->template = 'grid'; $this->getState()->setData($rows); return [ 'periodStart' => $this->getDate()->getLocalDate($fromDt), 'periodEnd' => $this->getDate()->getLocalDate($toDt), 'result' => $rows, ]; } /** * MySQL proof of play report * @param \Jenssegers\Date\Date $fromDt The filter range from date * @param \Jenssegers\Date\Date $toDt The filter range to date * @param $displayIds array * @param $layoutIds array * @param $mediaIds array * @param $type string * @param $columns array * @param $tags string * @param $tagsType string * @param $exactTags mixed * @param $start int * @param $length int * @return array[array result, date periodStart, date periodEnd, int count, int totalStats] */ private function getProofOfPlayReportMySql($fromDt, $toDt, $displayIds, $layoutIds, $mediaIds, $type, $columns, $tags, $tagsType, $exactTags, $start, $length) { $fromDt = $fromDt->format('U'); $toDt = $toDt->format('U'); // Media on Layouts Ran $select = ' SELECT stat.type, display.Display, IFNULL(layout.Layout, (SELECT `layout` FROM `layout` WHERE layoutId = (SELECT MAX(layoutId) FROM layouthistory WHERE campaignId = stat.campaignId))) AS Layout, IFNULL(`media`.name, IFNULL(`widgetoption`.value, `widget`.type)) AS Media, SUM(stat.count) AS NumberPlays, SUM(stat.duration) AS Duration, MIN(start) AS MinStart, MAX(end) AS MaxEnd, stat.tag, stat.layoutId, stat.mediaId, stat.widgetId, stat.displayId '; $body = ' FROM stat LEFT OUTER JOIN display ON stat.DisplayID = display.DisplayID LEFT OUTER JOIN layouthistory ON layouthistory.LayoutID = stat.LayoutID LEFT OUTER JOIN layout ON layout.LayoutID = layouthistory.layoutId LEFT OUTER JOIN `widget` ON `widget`.widgetId = stat.widgetId LEFT OUTER JOIN `widgetoption` ON `widgetoption`.widgetId = `widget`.widgetId AND `widgetoption`.type = \'attrib\' AND `widgetoption`.option = \'name\' LEFT OUTER JOIN `media` ON `media`.mediaId = `stat`.mediaId '; if ($tags != '' ) { if ($tagsType === 'dg') { $body .= 'INNER JOIN `lkdisplaydg` ON lkdisplaydg.DisplayID = display.displayid INNER JOIN `displaygroup` ON displaygroup.displaygroupId = lkdisplaydg.displaygroupId AND `displaygroup`.isDisplaySpecific = 1 '; } } $body .= ' WHERE stat.type <> \'displaydown\' AND stat.end > :fromDt AND stat.start <= :toDt '; // Filter by display if (count($displayIds) > 0 ) { $body .= ' AND stat.displayID IN (' . implode(',', $displayIds) . ') '; } $params = [ 'fromDt' => $fromDt, 'toDt' => $toDt ]; if ($tags != '') { if (trim($tags) === '--no-tag') { if ($tagsType === 'dg') { $body .= ' AND `displaygroup`.displaygroupId NOT IN ( SELECT `lktagdisplaygroup`.displaygroupId FROM tag INNER JOIN `lktagdisplaygroup` ON `lktagdisplaygroup`.tagId = tag.tagId ) '; } // old layout and latest layout have same tags // old layoutId replaced with latest layoutId in the lktaglayout table and // join with layout history to get campaignId then we can show old layouts that have no tag if ($tagsType === 'layout') { $body .= ' AND `stat`.campaignId NOT IN ( SELECT `layouthistory`.campaignId FROM ( SELECT `lktaglayout`.layoutId FROM tag INNER JOIN `lktaglayout` ON `lktaglayout`.tagId = tag.tagId ) B LEFT OUTER JOIN `layouthistory` ON `layouthistory`.layoutId = B.layoutId ) '; } if ($tagsType === 'media') { $body .= ' AND `media`.mediaId NOT IN ( SELECT `lktagmedia`.mediaId FROM tag INNER JOIN `lktagmedia` ON `lktagmedia`.tagId = tag.tagId ) '; } } else { $operator = $exactTags == 1 ? '=' : 'LIKE'; if ($tagsType === 'dg') { $body .= " AND `displaygroup`.displaygroupId IN ( SELECT `lktagdisplaygroup`.displaygroupId FROM tag INNER JOIN `lktagdisplaygroup` ON `lktagdisplaygroup`.tagId = tag.tagId "; } // old layout and latest layout have same tags // old layoutId replaced with latest layoutId in the lktaglayout table and // join with layout history to get campaignId then we can show old layouts that have given tag if ($tagsType === 'layout') { $body .= " AND `stat`.campaignId IN ( SELECT `layouthistory`.campaignId FROM ( SELECT `lktaglayout`.layoutId FROM tag INNER JOIN `lktaglayout` ON `lktaglayout`.tagId = tag.tagId "; } if ($tagsType === 'media') { $body .= " AND `media`.mediaId IN ( SELECT `lktagmedia`.mediaId FROM tag INNER JOIN `lktagmedia` ON `lktagmedia`.tagId = tag.tagId "; } $i = 0; foreach (explode(',', $tags) as $tag) { $i++; $tagV = explode('|', $tag); // search tag without value if (!isset($tagV[1])) { if ($i == 1) { $body .= ' WHERE `tag` ' . $operator . ' :tags' . $i; } else { $body .= ' OR `tag` ' . $operator . ' :tags' . $i; } if ($operator === '=') { $params['tags' . $i] = $tag; } else { $params['tags' . $i] = '%' . $tag . '%'; } // search tag only by value } elseif ($tagV[0] == '') { if ($i == 1) { $body .= ' WHERE `value` ' . $operator . ' :value' . $i; } else { $body .= ' OR `value` ' . $operator . ' :value' . $i; } if ($operator === '=') { $params['value' . $i] = $tagV[1]; } else { $params['value' . $i] = '%' . $tagV[1] . '%'; } // search tag by both tag and value } else { if ($i == 1) { $body .= ' WHERE `tag` ' . $operator . ' :tags' . $i . ' AND value ' . $operator . ' :value' . $i; } else { $body .= ' OR `tag` ' . $operator . ' :tags' . $i . ' AND value ' . $operator . ' :value' . $i; } if ($operator === '=') { $params['tags' . $i] = $tagV[0]; $params['value' . $i] = $tagV[1]; } else { $params['tags' . $i] = '%' . $tagV[0] . '%'; $params['value' . $i] = '%' . $tagV[1] . '%'; } } } if ($tagsType === 'layout') { $body .= " ) B LEFT OUTER JOIN `layouthistory` ON `layouthistory`.layoutId = B.layoutId ) "; } else { $body .= " ) "; } } } // Type filter if ($type == 'layout') { $body .= ' AND `stat`.type = \'layout\' '; } else if ($type == 'media') { $body .= ' AND `stat`.type = \'media\' AND IFNULL(`media`.mediaId, 0) <> 0 '; } else if ($type == 'widget') { $body .= ' AND `stat`.type = \'widget\' AND IFNULL(`widget`.widgetId, 0) <> 0 '; } else if ($type == 'event') { $body .= ' AND `stat`.type = \'event\' '; } // Layout Filter if (count($layoutIds) != 0) { $layoutSql = ''; $i = 0; foreach ($layoutIds as $layoutId) { $i++; $layoutSql .= ':layoutId_' . $i . ','; $params['layoutId_' . $i] = $layoutId; } $body .= ' AND `stat`.campaignId IN (SELECT campaignId from layouthistory where layoutId IN (' . trim($layoutSql, ',') . ')) '; } // Media Filter if (count($mediaIds) != 0) { $mediaSql = ''; $i = 0; foreach ($mediaIds as $mediaId) { $i++; $mediaSql .= ':mediaId_' . $i . ','; $params['mediaId_' . $i] = $mediaId; } $body .= ' AND `media`.mediaId IN (' . trim($mediaSql, ',') . ')'; } $body .= 'GROUP BY stat.type, stat.tag, display.Display, stat.displayId, stat.campaignId, IFNULL(stat.mediaId, stat.widgetId), IFNULL(`media`.name, IFNULL(`widgetoption`.value, `widget`.type)) '; $order = ''; if ($columns != null) $order = 'ORDER BY ' . implode(',', $columns); $limit= ''; if (($length != null) && ($length != -1)) $limit = ' LIMIT ' . $start . ', ' . $length; /*Execute sql statement*/ $sql = $select . $body . $order . $limit; $rows = []; foreach ($this->store->select($sql, $params) as $row) { $entry = []; $entry['type'] = $row['type']; $entry['displayId'] = $row['displayId']; $entry['display'] = $row['Display']; $entry['layout'] = $row['Layout']; $entry['media'] = $row['Media']; $entry['numberPlays'] = $row['NumberPlays']; $entry['duration'] = $row['Duration']; $entry['minStart'] = $row['MinStart']; $entry['maxEnd'] = $row['MaxEnd']; $entry['layoutId'] = $row['layoutId']; $entry['widgetId'] = $row['widgetId']; $entry['mediaId'] = $row['mediaId']; $entry['tag'] = $row['tag']; $rows[] = $entry; } // Paging $results = []; if ($limit != '' && count($rows) > 0) { $results = $this->store->select(' SELECT COUNT(*) AS total FROM (SELECT stat.type, display.Display, layout.Layout, IFNULL(`media`.name, IFNULL(`widgetoption`.value, `widget`.type)) ' . $body . ') total ', $params); } return [ 'result' => $rows, 'periodStart' => $this->getDate()->parse($fromDt, 'U')->format('Y-m-d H:i:s'), 'periodEnd' => $this->getDate()->parse($toDt, 'U')->format('Y-m-d H:i:s'), 'count' => count($rows), 'totalStats' => isset($results[0]['total']) ? $results[0]['total'] : 0, ]; } /** * MongoDB proof of play report * @param \Jenssegers\Date\Date $fromDt The filter range from date * @param \Jenssegers\Date\Date $toDt The filter range to date * @param $displayIds array * @param $layoutIds array * @param $mediaIds array * @param $type string * @param $columns array * @param $tags string * @param $tagsType string * @param $exactTags mixed * @param $start int * @param $length int * @return array[array result, date periodStart, date periodEnd, int count, int totalStats] */ private function getProofOfPlayReportMongoDb($fromDt, $toDt, $displayIds, $layoutIds, $mediaIds, $type, $columns, $tags, $tagsType, $exactTags, $start, $length) { $fromDt = new UTCDateTime($fromDt->format('U')*1000); $toDt = new UTCDateTime($toDt->format('U')*1000); // Filters the documents to pass only the documents that // match the specified condition(s) to the next pipeline stage. $match = [ '$match' => [ 'end' => [ '$gt' => $fromDt], 'start' => [ '$lte' => $toDt] ] ]; // Display Filter if (count($displayIds) > 0) { $match['$match']['displayId'] = [ '$in' => $displayIds ]; } // Type Filter if ($type != null) { $match['$match']['type'] = $type; } $tagsArray = []; // Tag Filter if ($tags != null) { $i = 0; foreach (explode(',', $tags) as $tag ) { $tagV = explode('|', $tag); if (!isset($tagV[1])) { $tagsArray[$i]['tag'] = $tag; } elseif ($tagV[0] == '') { $tagsArray[$i]['val'] = $tagV[1]; } else { $tagsArray[$i]['tag'] = $tagV[0]; $tagsArray[$i]['val'] = $tagV[1]; } $i++; } if ($exactTags != 1) { $tagsArray = array_map(function ($tagValue) { return array_map(function ($tag) { return new \MongoDB\BSON\Regex('.*'.$tag. '.*', 'i'); }, $tagValue); }, $tagsArray); } // When exact match is not desired if (count($tagsArray) > 0) { $match['$match']['tagFilter.' . $tagsType] = [ '$elemMatch' => [ '$or' => $tagsArray ] ]; } } // Layout Filter if (count($layoutIds) != 0) { $this->getLog()->debug(json_encode($layoutIds, JSON_PRETTY_PRINT)); // Get campaignIds for selected layoutIds $campaignIds = []; foreach ($layoutIds as $layoutId) { try { $campaignIds[] = $this->layoutFactory->getCampaignIdFromLayoutHistory($layoutId); } catch (NotFoundException $notFoundException) { // Ignore the missing one $this->getLog()->debug('Filter for Layout without Layout History Record, layoutId is ' . $layoutId); } } $match['$match']['campaignId'] = [ '$in' => $campaignIds ]; } // Media Filter if (count($mediaIds) != 0) { $this->getLog()->debug(json_encode($mediaIds, JSON_PRETTY_PRINT)); $match['$match']['mediaId'] = [ '$in' => $mediaIds ]; } // For sorting // The selected column has a key $temp = [ '_id.type' => 'type', '_id.display' => 'display', 'layout' => 'layout', 'media' => 'media', 'eventName' => 'eventName', 'layoutId' => 'layoutId', 'widgetId' => 'widgetId', '_id.displayId' => 'displayId', 'numberPlays' => 'numberPlays', 'minStart' => 'minStart', 'maxEnd' => 'maxEnd', 'duration' => 'duration', ]; // Remove ` and DESC from the array strings $cols = []; foreach ($columns as $column) { $str = str_replace("`","",str_replace(" DESC","",$column)); if (\strpos($column, 'DESC') !== false) { $cols[$str] = -1; } else { $cols[$str] = 1; } } // The selected column key gets stored in an array with value 1 or -1 (for DESC) $array = []; foreach ($cols as $k => $v) { if (array_search($k, $temp)) $array[array_search($k, $temp)] = $v; } $order = ['_id.type'=> 1]; // default sorting by type if ($array != null) { $order = $array; } $project = [ '$project' => [ 'campaignId' => 1, 'mediaId' => 1, 'mediaName'=> 1, 'media'=> [ '$ifNull' => [ '$mediaName', '$widgetName' ] ], 'eventName' => 1, 'widgetId' => 1, 'widgetName' => 1, 'layoutId' => 1, 'layoutName' => 1, 'displayId' => 1, 'displayName' => 1, 'start' => 1, 'end' => 1, 'type' => 1, 'duration' => 1, 'count' => 1, 'total' => ['$sum' => 1], ] ]; $group = [ '$group' => [ '_id' => [ 'type' => '$type', 'campaignId'=> [ '$ifNull' => [ '$campaignId', '$layoutId' ] ], 'mediaorwidget'=> [ '$ifNull' => [ '$mediaId', '$widgetId' ] ], 'displayId'=> [ '$ifNull' => [ '$displayId', null ] ], 'display'=> '$displayName', 'eventName'=> '$eventName', // we don't need to group by media name and widget name ], 'media'=> [ '$first' => '$media'], 'eventName'=> [ '$first' => '$eventName'], 'mediaId' => ['$first' => '$mediaId'], 'widgetId' => ['$first' => '$widgetId' ], 'layout' => ['$first' => '$layoutName'], // use the last layoutId to say that is the latest layoutId 'layoutId' => ['$last' => '$layoutId'], 'minStart' => ['$min' => '$start'], 'maxEnd' => ['$max' => '$end'], 'numberPlays' => ['$sum' => '$count'], 'duration' => ['$sum' => '$duration'], 'total' => ['$max' => '$total'], ], ]; // Task run if ($length == -1) { $query = [ $match, $project, $group, [ '$facet' => [ 'totalData' => [ ['$sort' => $order], ] ] ], ]; } else { // Frontend $query = [ $match, $project, $group, [ '$facet' => [ 'totalData' => [ ['$skip' => $start], ['$limit' => $length], ['$sort' => $order], ], 'totalCount' => [ [ '$group' => [ '_id' => [], 'totals' => ['$sum' => '$total'], ], ] ] ] ], ]; } $result = $this->getTimeSeriesStore()->executeQuery(['collection' => $this->table, 'query' => $query]); $totalStats = 0; $rows = []; if (count($result) > 0) { if ($length == -1) { // Task run $totalCount = []; } else { // Get total for pagination in UI (grid) $totalCount = $result[0]['totalCount']; } if (count($totalCount) > 0) { $totalStats = $totalCount[0]['totals']; } // Grid results foreach ($result[0]['totalData'] as $row) { $entry = []; $entry['type'] = $row['_id']['type']; $entry['displayId'] = $row['_id']['displayId']; $entry['display'] = isset($row['_id']['display']) ? $row['_id']['display']: 'No display'; $entry['layout'] = isset($row['layout']) ? $row['layout']: 'No layout'; $entry['media'] = isset($row['media']) ? $row['media'] : 'No media' ; $entry['numberPlays'] = $row['numberPlays']; $entry['duration'] = $row['duration']; $entry['minStart'] = $row['minStart']->toDateTime()->format('U'); $entry['maxEnd'] = $row['maxEnd']->toDateTime()->format('U'); $entry['layoutId'] = $row['layoutId']; $entry['widgetId'] = $row['widgetId']; $entry['mediaId'] = $row['mediaId']; $entry['tag'] = $row['eventName']; $rows[] = $entry; } } return [ 'result' => $rows, 'periodStart' => $this->getDate()->parse($fromDt->toDateTime()->format('U'), 'U')->format('Y-m-d H:i:s'), 'periodEnd' => $this->getDate()->parse($toDt->toDateTime()->format('U'), 'U')->format('Y-m-d H:i:s'), 'count' => count($rows), 'totalStats' => $totalStats, ]; } }