/** * A method to return the number of operation intervals * during per day. * * @static * @return integer The number of operation intervals per week. */ function operationIntervalsPerWeek() { return 7 * OX_OperationInterval::operationIntervalsPerDay(); }
/** * A method to obtain the sum of the zone forecast impression value, for all the zones * an advertisement is linked to, cloned out over the advertisement's entire remaining * lifetime in the campaign, with any blocked operation intervals removed. * * Requires that the getActiveAdOperationIntervals() method have previously been * called to function correctly. * * @param PEAR::Date $oNowDate The current date. * @param PEAR::Date $oEndDate The end date of the campaign. Note that if the end * date supplied is not at the end of a day, it will be * converted to be treated as such. * @param array $aCumulativeZoneForecast The cumulative forecast impressions, indexed * by operation interval ID, of all the zones the * advertisement is linked to. * array( * [operation_interval_id] => forecast_impressions, * [operation_interval_id] => forecast_impressions * . * . * . * ) * @return integer The ad's total remaining zone impression forecast for all zone for * the remaining life of the ad. */ function getAdLifetimeZoneImpressionsRemaining($oNowDate, $oEndDate, $aCumulativeZoneForecast) { $totalAdLifetimeZoneImpressionsRemaining = 0; // Test the parameters, if invalid, return zero if (!is_a($oNowDate, 'date') || !is_a($oEndDate, 'date') || !is_array($aCumulativeZoneForecast) || count($aCumulativeZoneForecast) != OX_OperationInterval::operationIntervalsPerWeek()) { OA::debug(' - Invalid parameters to getAdLifetimeZoneImpressionsRemaining, returning 0', PEAR_LOG_ERR); return $totalAdLifetimeZoneImpressionsRemaining; } // Ensure that the end of campaign date is at the end of the day $oEndDateCopy = new Date($oEndDate); $oEndDateCopy->setHour(23); $oEndDateCopy->setMinute(59); $oEndDateCopy->setSecond(59); // Ensure that the $aCumulativeZoneForecast array is sorted by key, so that it can // be accessed by array_slice, regardless of the order that the forecast data was added // to the array ksort($aCumulativeZoneForecast); // Step 1: Calculate the sum of the forecast values from "now" until the end of "today" $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oNowDate); $oEndOfToday = new Date($aDates['start']); $oEndOfToday->setTZ($oEndDate->tz); $oEndOfToday->setHour(23); $oEndOfToday->setMinute(59); $oEndOfToday->setSecond(59); $oStart = $aDates['start']; while ($oStart->before($oEndOfToday)) { // Find the Operation Interval ID for this Operation Interval $operationIntervalID = OX_OperationInterval::convertDateToOperationIntervalID($oStart); // As iteration over every OI is required anyway, test to see if // the ad is blocked in this OI; if not, add the forecast values to the // running total if (empty($this->aBlockedOperationIntervalDates[$oStart->format('%Y-%m-%d %H:%M:%S')])) { $totalAdLifetimeZoneImpressionsRemaining += $aCumulativeZoneForecast[$operationIntervalID]; } // Go to the next operation interval in "today" $oStart = OX_OperationInterval::addOperationIntervalTimeSpan($oStart); } // Step 2: Calculate how many times each day of the week occurs between the end of // "today" (i.e. starting "tomorrow morning") and the last day the ad can run $aDays = array(); $oStartOfTomorrow = new Date($oEndOfToday); $oStartOfTomorrow->addSeconds(1); $oTempDate = new Date(); $oTempDate->copy($oStartOfTomorrow); $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oTempDate); while ($aDates['start']->before($oEndDateCopy)) { // Increase the count for this day of the week $aDays[$aDates['start']->getDayOfWeek()]++; // Go to the next day $oTempDate->addSeconds(SECONDS_PER_DAY); $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oTempDate); } // Step 3: For every possible day of the week (assuming that day of the week is in the // ad's remaining lifetime), calculate the sum of the forecast values for every // operation interval in that day if (!empty($aDays)) { $operationIntervalsPerDay = OX_OperationInterval::operationIntervalsPerDay(); $oTempDate = new Date($oStartOfTomorrow); $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oTempDate); for ($counter = 0; $counter < 7; $counter++) { // Are there any instances of this day in the campaign? if ($aDays[$oTempDate->getDayOfWeek()] > 0) { // Calculate the sum of the zone forecasts for this day of week $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oTempDate); $dayStartOperationIntervalId = OX_OperationInterval::convertDateToOperationIntervalID($aDates['start']); $aDayCumulativeZoneForecast = array_slice($aCumulativeZoneForecast, $dayStartOperationIntervalId, $operationIntervalsPerDay); $forecastSum = array_sum($aDayCumulativeZoneForecast); // Multiply this day's forecast sum value by the number of times this // day of week appears in the remainder of the campaign and add the // value to the running total $totalAdLifetimeZoneImpressionsRemaining += $forecastSum * $aDays[$oTempDate->getDayOfWeek()]; } // Go to the next day $oTempDate->addSeconds(SECONDS_PER_DAY); } } // Step 4: Subtract any blocked interval values if ($this->blockedOperationIntervalCount > 0) { OA::debug(" - Subtracting {$this->blockedOperationIntervalCount} blocked intervals", PEAR_LOG_DEBUG); foreach ($this->aBlockedOperationIntervalDates as $aDates) { if ($aDates['start']->after($oEndOfToday)) { $blockedOperationInvervalID = OX_OperationInterval::convertDateToOperationIntervalID($aDates['start']); $totalAdLifetimeZoneImpressionsRemaining -= $aCumulativeZoneForecast[$blockedOperationInvervalID]; } } } // Return the calculated value return $totalAdLifetimeZoneImpressionsRemaining; }