/** * A method to store data about the times that various Maintenance * processes ran. * * @param Date $oStart The time that the script run started. * @param Date $oEnd The time that the script run ended. * @param mixed $oUpdateTo PEAR::Date representing the end of the last * operation interval ID that has been updated, * or NULL, in the case that this information * does not actually apply, and only the * start/end dates of the process run are * relevant. * @param string $tableName The name of the log_matinenance_* table to log into. * Must NOT be a complete table name, ie. no prefix. * @param boolean $setOperationInterval Should the operation intverval value be * logged, or not? * @param string $runTypeField Optional name of DB field to hold $type value. * @param integer $type Optional type of process run performed. */ function setProcessLastRunInfo($oStart, $oEnd, $oUpdateTo, $tableName, $setOperationInterval, $runTypeField = null, $type = null) { $aConf = $GLOBALS['_MAX']['CONF']; // Test input values $oStart and $oEnd are dates if (!is_a($oStart, 'Date') || !is_a($oEnd, 'Date')) { return false; } // Test $oUpdateTo is a date, or null if (!is_a($oUpdateTo, 'Date')) { if (!is_null($oUpdateTo)) { return false; } } // Test $setOperationInterval value is a boolean if (!is_bool($setOperationInterval)) { return false; } // Prepare the duraction to log from the start and end dates $oDuration = new Date_Span(); $oStartDateCopy = new Date(); $oStartDateCopy->copy($oStart); $oEndDateCopy = new Date(); $oEndDateCopy->copy($oEnd); $oDuration->setFromDateDiff($oStartDateCopy, $oEndDateCopy); // Prepare the logging query $tableName = $this->_getTablename($tableName); $query = "\n INSERT INTO\n {$tableName}\n (\n start_run,\n end_run,"; if ($setOperationInterval) { $query .= "\n operation_interval,"; } $query .= "\n duration"; if (!is_null($runTypeField) && !is_null($type)) { $query .= ",\n {$runTypeField}"; } if (!is_null($oUpdateTo)) { $query .= ",\n updated_to"; } $query .= "\n )\n VALUES\n (\n '" . $oStart->format('%Y-%m-%d %H:%M:%S') . "',\n '" . $oEnd->format('%Y-%m-%d %H:%M:%S') . "',"; if ($setOperationInterval) { $query .= "\n {$aConf['maintenance']['operationInterval']},"; } $query .= "\n " . $oDuration->toSeconds(); if (!is_null($runTypeField) && !is_null($type)) { $query .= ",\n {$type}"; } if (!is_null($oUpdateTo)) { $query .= ",\n '" . $oUpdateTo->format('%Y-%m-%d %H:%M:%S') . "'"; } $query .= "\n )"; OA::debug('- Logging maintenance process run information into ' . $tableName, PEAR_LOG_DEBUG); $rows = $this->oDbh->exec($query); if (PEAR::isError($rows)) { return false; } else { return $rows; } }
/** * The implementation of the OA_Task::run() method that performs * the required task of managing conversions. */ function run() { if ($this->oController->updateIntermediate) { // Preapre the start date for the management of conversions $oStartDate = new Date(); $oStartDate->copy($this->oController->oLastDateIntermediate); $oStartDate->addSeconds(1); // Get the MSE DAL to perform the conversion management $oServiceLocator =& OA_ServiceLocator::instance(); $oDal =& $oServiceLocator->get('OX_Dal_Maintenance_Statistics'); // Manage conversions $oDal->manageConversions($oStartDate, $this->oController->oUpdateIntermediateToDate); } }
/** * The implementation of the OA_Task::run() method that performs * the required task of migrating data_intermediate_% table data * into the data_summary_% tables. */ function run() { if ($this->oController->updateIntermediate || $this->oController->updateFinal) { $message = '- Saving request, impression, click and conversion data into the final tables.'; $this->oController->report .= $message . "\n"; OA::debug($message, PEAR_LOG_DEBUG); } if ($this->oController->updateFinal) { // Update the hourly summary table $oStartDate = new Date(); $oStartDate->copy($this->oController->oLastDateFinal); $oStartDate->addSeconds(1); $this->_saveSummary($oStartDate, $this->oController->oUpdateFinalToDate); } }
/** * The implementation of the OA_Task::run() method that performs * the required task of de-duplicating and rejecting conversions. */ function run() { if ($this->oController->updateIntermediate) { // Preapre the start date for the de-duplication/rejection $oStartDate = new Date(); $oStartDate->copy($this->oController->oLastDateIntermediate); $oStartDate->addSeconds(1); // Get the MSE DAL to perform the de-duplication $oServiceLocator =& OA_ServiceLocator::instance(); $oDal =& $oServiceLocator->get('OX_Dal_Maintenance_Statistics'); // De-duplicate conversions $oDal->deduplicateConversions($oStartDate, $this->oController->oUpdateIntermediateToDate); // Reject empty variable conversions $oDal->rejectEmptyVarConversions($oStartDate, $this->oController->oUpdateIntermediateToDate); } }
/** * A private method that calcualtes the ZIF value(s) for a given zone. * * For each operation interval that requires the zone's ZIF value to be updated, * the ZIF value for the zone is calculated via the following algorithm: * * - If the zone has been operational for at least ZONE_FORECAST_BASELINE_WEEKS weeks * (i.e. the zone has actual impressions for the past ZONE_FORECAST_BASELINE_WEEKS * occurrences of the same operation interval as is currently being updated), then * the expected impressions value is the average of the past two operation intervals' * actual impressions of the zone, multiplied by a moving average trend value. * - Else, if the zone has not been operational for at least * ZONE_FORECAST_BASELINE_WEEKS weeks, then the expected impressions is set to the * actual number of impressions in the previous operation interval for that zone. * - Else the previous operation interval for that zone does not have an actual * number of impressions, then the expected number of impressions for that * zone is set to ZONE_FORECAST_DEFAULT_ZONE_IMPRESSIONS. * * Note also: * - If the zone ID exists in the $this->aNewZoneIDs array, then all operation * intervals for the past week will be updated, not just those in $aRanges. * * @access private * @param integer $zoneId The ID of the zone which may require its ZIF value(s) * to be calculated. * @param array $aRanges An array of arrays, containing ranges of operation * intervals that the zone will need its ZIF values * updated for. * @param boolean $newZone The zone is considered to be "new"; store this * information along with the forecasts. * * @return void */ function _calculateZoneImpressionForecastValues($zoneId, $aRanges, $newZone) { // Check the parameters if (!is_integer($zoneId) || $zoneId < 0) { return; } if (!is_array($aRanges) || empty($aRanges)) { return; } // Update the ZIF for all ranges foreach ($aRanges as $aRange) { // Get the two dates representing operation interval start // dates for the two operation interval IDs at the lower and // upper bounds of the range $tmp = array_keys($aRange); $min = min($tmp); $max = max($tmp); $oRangeLowerDate = new Date(); $oRangeLowerDate->copy($aRange[$min]['start']); $oRangeUpperDate = new Date(); $oRangeUpperDate->copy($aRange[$max]['start']); // Get the average impressions delivered by the zone in previous // operation intervals, for the required operation interval range $aZoneImpressionAverages = $this->_getZoneImpressionAverages($zoneId, $oRangeLowerDate, $oRangeUpperDate); // Get the details of all forecast and actual impressions of the // zone for the required operation interval range, offset by the // required time interval, so that current trends in differences // between forecast and actual delivery can be calculated $oTrendLowerDate = $this->_getTrendLowerDate($oRangeLowerDate); $oTrendUpperDate = $this->_getTrendUpperDate($oRangeUpperDate); $aZoneForecastAndImpressionHistory = $this->oDal->getZonePastForecastAndImpressionHistory($zoneId, $oTrendLowerDate, $oTrendUpperDate); foreach ($aRange as $intervalId => $aInterval) { if (!isset($aZoneImpressionAverages[$intervalId])) { // This zone does not have a past average actual impressions delivered // value for this operation interval ID, and so cannot have been running // for longer than ZONE_FORECAST_BASELINE_WEEKS - as a result, either // forecast the value based on the past operation interval's data, or // use the default value $previousIntervalID = OX_OperationInterval::previousOperationIntervalID($intervalId); if (isset($aZoneForecastAndImpressionHistory[$previousIntervalID]['actual_impressions']) && $aZoneForecastAndImpressionHistory[$previousIntervalID]['actual_impressions'] > 0) { // Use the previous operation interval's actual impressions value as the // new forecast OA::debug(" - Forecasting for OI {$intervalId} (starting '" . $aInterval['start']->format('%Y-%m-%d %H:%M:%S') . ' ' . $aInterval['start']->tz->getShortName() . "') based on previous OI value", PEAR_LOG_DEBUG); $this->_storeForecast($this->aForecastResults, $aZoneForecastAndImpressionHistory, $zoneId, $intervalId, $aInterval, $aZoneForecastAndImpressionHistory[$previousIntervalID]['actual_impressions'], $newZone); } else { // Use the default value as the new forecast, and note that the forecast // is so based OA::debug(" - Forecasting for OI {$intervalId} (starting '" . $aInterval['start']->format('%Y-%m-%d %H:%M:%S') . ' ' . $aInterval['start']->tz->getShortName() . "') based on default value", PEAR_LOG_DEBUG); $this->_storeForecast($this->aForecastResults, $aZoneForecastAndImpressionHistory, $zoneId, $intervalId, $aInterval, $this->ZONE_FORECAST_DEFAULT_ZONE_IMPRESSIONS, $newZone, true); } } else { // Get the lower bound operation interval ID of the trend calculation // range required for this operation interval ID $offetOperationId = OX_OperationInterval::previousOperationIntervalID($intervalId, null, $this->_getTrendOperationIntervalStartOffset()); // Set the initial forecast and actual impressions values $forecastImpressions = 0; $actualImpressions = 0; // Loop over the trend adjustment range data appropriate to this operation // interval ID, and sum up the forecast and actual impression values for ($i = 0; $i < ZONE_FORECAST_TREND_OPERATION_INTERVALS; $i++) { if (!isset($aZoneForecastAndImpressionHistory[$offetOperationId])) { // The forecast/impression history of this zone is incomplete, so the // trend adjustment information cannot be calculated $forecastImpressions = false; $actualImpressions = false; break; } // Sum the actual impression value for the current trend adjustment interval if (!empty($aZoneForecastAndImpressionHistory[$offetOperationId]['actual_impressions'])) { $actualImpressions += $aZoneForecastAndImpressionHistory[$offetOperationId]['actual_impressions']; } // Sum the forecast impression value for the current trend adjustment interval if ($aZoneForecastAndImpressionHistory[$offetOperationId]['forecast_impressions'] < 1) { // Ack, that's a bad forecast impression value - don't trust the data! $forecastImpressions = false; $actualImpressions = false; break; } $forecastImpressions += $aZoneForecastAndImpressionHistory[$offetOperationId]['forecast_impressions']; // Go to the next operation ID in the trend range $offetOperationId = OX_OperationInterval::nextOperationIntervalID($offetOperationId); } unset($forecastAverage); if ($forecastImpressions !== false) { // Calculate the average forecast impression value for the trend adjustment range $forecastAverage = $forecastImpressions / ZONE_FORECAST_TREND_OPERATION_INTERVALS; } unset($actualAverage); if ($actualImpressions !== false) { // Calculate the average actual impression value for the trend adjustment range $actualAverage = round($actualImpressions / ZONE_FORECAST_TREND_OPERATION_INTERVALS); } if (isset($forecastAverage) && $forecastAverage > 0 && isset($actualAverage)) { // The past average forecast and actual impression values exist, so calculate the // trend adjustment value, and calculate the new forecast from the past average and // the trend adjustment value OA::debug(" - Forecasting for OI {$intervalId} (starting '" . $aInterval['start']->format('%Y-%m-%d %H:%M:%S') . ' ' . $aInterval['start']->tz->getShortName() . "') based on past average and recent trend", PEAR_LOG_DEBUG); $trendValue = $actualAverage / $forecastAverage; $this->_storeForecast($this->aForecastResults, $aZoneForecastAndImpressionHistory, $zoneId, $intervalId, $aInterval, $aZoneImpressionAverages[$intervalId] * $trendValue, $newZone); } else { // The trend data could not be calculated, so simply use the past average as the // new forecast OA::debug(" - Forecasting for OI {$intervalId} (starting '" . $aInterval['start']->format('%Y-%m-%d %H:%M:%S') . ' ' . $aInterval['start']->tz->getShortName() . "') based on past average only", PEAR_LOG_DEBUG); $this->_storeForecast($this->aForecastResults, $aZoneForecastAndImpressionHistory, $zoneId, $intervalId, $aInterval, $aZoneImpressionAverages[$intervalId], $newZone); } } } } }
function get_weekly_volume_graph() { global $wpdb; global $userdata; get_currentuserinfo(); $beg_date = new Date(); $end_date = new Date(); $wk = array(0, 0, 0, 0); $label = array(0, 0, 0, 0); $filename = array("filename" => "/var/www/vanhlebarsoftware/wp-content/plugins/fitnesslog/graphs/wklygraph.png"); // Get current weeks and prior three weeks volume numbers. $day_of_wk = $beg_date->getDayOfWeek(); $beg_date->addDays(-($day_of_wk - 1)); $end_date->copy($beg_date); $end_date->addDays(6); for ($i = 0; $i < 4; $i++) { $query = "SELECT user_id, SUM(seconds) AS seconds FROM " . $wpdb->prefix . "flmain WHERE workout_date>='" . $beg_date->format("%Y-%m-%d") . "' AND workout_date<='" . $end_date->format("%Y-%m-%d") . "' AND user_id=" . $userdata->ID . " GROUP BY user_id"; $result = $wpdb->get_results($query, ARRAY_A); if ($result) { foreach ($result as $row) { $wk[$i] = convert_seconds_minutes($row["seconds"]); } } else { $wk[$i] = 0; } // Add any strength training that we have done to the total. $query = "SELECT user_id, SUM(seconds) AS seconds FROM " . $wpdb->prefix . "flstrength WHERE workout_date>='" . $beg_date->format("%Y-%m-%d") . "' AND workout_date<='" . $end_date->format("%Y-%m-%d") . "' AND user_id=" . $userdata->ID . " GROUP BY user_id"; $result = $wpdb->get_results($query, ARRAY_A); if ($result) { foreach ($result as $row) { $wk[$i] = $wk[$i] + convert_seconds_minutes($row["seconds"]); } } // Create the labels. $label[$i] = $end_date->format("%m/%d"); // Move the dates back by one week. $beg_date->addDays(-7); $end_date->addDays(-7); } //Setup the graph. $Graph =& Image_Graph::factory('graph', array(175, 175), true); $Plotarea =& $Graph->addNew('plotarea'); $Dataset =& Image_Graph::factory('dataset'); $Dataset->addPoint($label[3], $wk[3]); $Dataset->addPoint($label[2], $wk[2]); $Dataset->addPoint($label[1], $wk[1]); $Dataset->addPoint($label[0], $wk[0]); $Plot =& $Plotarea->addNew('bar', &$Dataset); $Plot->setFillColor('green'); $YAxis =& $Plotarea->getAxis(IMAGE_GRAPH_AXIS_Y); $YAxis->setTitle('Minutes', 'vertical'); $XAxis =& $Plotarea->getAxis(IMAGE_GRAPH_AXIS_X); // $XAxis->setFontAngle( "vertical" ); $XAxis->setTitle("Week", array('angle' => 0)); //Output the finished graph to the graphs directory. $result = $Graph->done($filename); if ($result) { var_dump("error creating graph!"); } }
/** * A method to check that two Dates represent either the start and end * of an operation interval, if the operation interval is less than an * hour, or the start and end of an hour otherwise. * * @static * @param Date $oStart The interval start date. * @param Date $oEnd The interval end date. * @param integer $operationInterval The operation interval in minutes. * @return bool Returns true if the dates are correct interval * start/end dates, false otherwise. */ function checkIntervalDates($oStart, $oEnd, $operationInterval = 0) { if ($operationInterval < 1) { $operationInterval = OX_OperationInterval::getOperationInterval(); } if ($operationInterval <= 60) { // Must ensure that only one operation interval is being summarised $operationIntervalID = OX_OperationInterval::convertDateRangeToOperationIntervalID($oStart, $oEnd, $operationInterval); if (is_bool($operationIntervalID) && !$operationIntervalID) { return false; } // Now check that the start and end dates match the start and end // of the operation interval $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oStart, $operationInterval); if (!$oStart->equals($aDates['start'])) { return false; } if (!$oEnd->equals($aDates['end'])) { return false; } } else { // Must ensure that only one hour is being summarised if (!OX_OperationInterval::checkDatesInSameHour($oStart, $oEnd)) { return false; } // Now check that the start and end dates are match the start and // end of the hour $oHourStart = new Date(); $oHourStart->copy($oStart); $oHourStart->setMinute('00'); $oHourStart->setSecond('00'); $oHourEnd = new Date(); $oHourEnd->copy($oEnd); $oHourEnd->setMinute('59'); $oHourEnd->setSecond('59'); if (!$oStart->equals($oHourStart)) { return false; } if (!$oEnd->equals($oHourEnd)) { return false; } } return true; }
/** * Method to test the getZonesForecastsForAllZones method. * * Requirements: * Test 1: Test with no Date registered in the service locator, ensure false returned. * Test 2: Test with a Date registered in the service locator, no data in the database, * and ensure no data is returned. * Test 3: Test with forecast data but no actual impressions * Test 3.5: Test with actual data but no forecast impressions * Test 4: Test with data both in, and not in, the current OI, and ensure the correct * data is returned. * Test 5: Repeat Test 4, but with additional zones (that don't have data) in the zones * table. */ function testGetAllZonesImpInv() { $conf = $GLOBALS['_MAX']['CONF']; $oDbh =& OA_DB::singleton(); $oMaxDalMaintenance = new OA_Dal_Maintenance_Priority(); $zoneForecastDefaultZoneImpressions = 0; // $oMaxDalMaintenance->getZoneForecastDefaultZoneImpressions(); // Test 1 $oServiceLocator =& OA_ServiceLocator::instance(); $oServiceLocator->remove('now'); $result =& $oMaxDalMaintenance->getZonesForecastsForAllZones(); $this->assertFalse($result); // Test 2 $oDate = new Date(); $oServiceLocator->register('now', $oDate); $result =& $oMaxDalMaintenance->getZonesForecastsForAllZones(); $this->assertEqual($result, array(0 => $zoneForecastDefaultZoneImpressions)); // Zone 0 // Test 3 // generate the first zone $aZones = $this->_generateTestZones(1); // only generate previous OI delivered impressions, should return zone 0 only $oDate =& $oServiceLocator->get('now'); $oNewDate = new Date(); $oNewDate->copy($oDate); $oNewDate->subtractSeconds($conf['maintenance']['operationInterval'] * 60 + 1); $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oNewDate); $this->_generateTestHistory(1, $aDates, 42, 0); $result =& $oMaxDalMaintenance->getZonesForecastsForAllZones(); $expected = array(0 => $zoneForecastDefaultZoneImpressions, 1 => $zoneForecastDefaultZoneImpressions); $this->assertEqual($result, $expected); // Test 3.5 // generate the second zone $aZones = $this->_generateTestZones(1); // only generate previous OI forecasted impressions, should return zone 0 only $oNewDate = new Date(); $oNewDate->copy($aDates['start']); $oNewDate->subtractSeconds(1); $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oNewDate); $this->_generateTestHistory(2, $aDates, 0, 37); $result =& $oMaxDalMaintenance->getZonesForecastsForAllZones(); $expected = array(0 => $zoneForecastDefaultZoneImpressions, 1 => $zoneForecastDefaultZoneImpressions, 2 => $zoneForecastDefaultZoneImpressions); $this->assertEqual($result, $expected); $oDate =& $oServiceLocator->get('now'); DataGenerator::cleanUp(); $oServiceLocator->register('now', $oDate); // Test 4 $oDate =& $oServiceLocator->get('now'); // generate three zone $this->_generateTestZones(3); // set forecast and impressions for OI - 1 $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oDate); $this->_generateTestHistory(1, $aDates, 42, 100); $this->_generateTestHistory(2, $aDates, 5, 2); $this->_generateTestHistory(3, $aDates, 9999, 9999); $result =& $oMaxDalMaintenance->getZonesForecastsForAllZones(); $expected = array(0 => $zoneForecastDefaultZoneImpressions, 1 => 42, 2 => 5, 3 => 9999); $this->assertEqual($result, $expected); // Test 5 // New zone must appear in the array with default forecast $aZones = $this->_generateTestZones(1); $result =& $oMaxDalMaintenance->getZonesForecastsForAllZones(); $expected = array(0 => $zoneForecastDefaultZoneImpressions, 1 => 42, 2 => 5, 3 => 9999, 4 => $zoneForecastDefaultZoneImpressions); $result =& $oMaxDalMaintenance->getZonesForecastsForAllZones(); $this->assertEqual($result, $expected); // register forecast for the OI before, this should not affect current OI forecast $oDate =& $oServiceLocator->get('now'); $aDates = OX_OperationInterval::convertDateToPreviousOperationIntervalStartAndEndDates($oDate); $currentOpIntID = OX_OperationInterval::convertDateToOperationIntervalID($aDates['start']); $this->_generateTestHistory(1, $aDates, 3700, 0); $this->_generateTestHistory(2, $aDates, 300, 0); $this->_generateTestHistory(3, $aDates, 500, 0); $result =& $oMaxDalMaintenance->getZonesForecastsForAllZones(); $this->assertEqual($result, $expected); DataGenerator::cleanUp(); }
/** * 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; }
/** * A method to test the run() method. */ function testRun() { $oServiceLocator =& OA_ServiceLocator::instance(); $aTypes = array('types' => array(0 => 'request', 1 => 'impression', 2 => 'click'), 'connections' => array(1 => MAX_CONNECTION_AD_IMPRESSION, 2 => MAX_CONNECTION_AD_CLICK)); // Mock the DAL, and set expectations Mock::generate('OX_Dal_Maintenance_Statistics'); $oDal = new MockOX_Dal_Maintenance_Statistics($this); $oDal->expectNever('saveSummary'); $oServiceLocator->register('OX_Dal_Maintenance_Statistics', $oDal); // Set the controller class $oMaintenanceStatistics = new OX_Maintenance_Statistics(); $oServiceLocator->register('Maintenance_Statistics_Controller', $oMaintenanceStatistics); // Test $oSummariseFinal = new OX_Maintenance_Statistics_Task_SummariseFinal(); $oSummariseFinal->oController->updateIntermediate = false; $oSummariseFinal->oController->updateFinal = false; $oSummariseFinal->run(); $oDal->tally(); // Prepare the dates $olastDateIntermediate = new Date('2006-03-09 10:59:59'); $oStartDate = new Date(); $oStartDate->copy($olastDateIntermediate); $oStartDate->addSeconds(1); $oUpdateIntermediateToDate = new Date('2006-03-09 11:59:59'); // Mock the DAL, and set expectations Mock::generate('OX_Dal_Maintenance_Statistics'); $oDal = new MockOX_Dal_Maintenance_Statistics($this); $oDal->expectNever('saveSummary'); $oServiceLocator->register('OX_Dal_Maintenance_Statistics', $oDal); // Set the controller class $oMaintenanceStatistics = new OX_Maintenance_Statistics(); $oServiceLocator->register('Maintenance_Statistics_Controller', $oMaintenanceStatistics); // Test $oSummariseFinal = new OX_Maintenance_Statistics_Task_SummariseFinal(); $oSummariseFinal->oController->updateIntermediate = true; $oSummariseFinal->oController->oLastDateIntermediate = $olastDateIntermediate; $oSummariseFinal->oController->oUpdateIntermediateToDate = $oUpdateIntermediateToDate; $oSummariseFinal->oController->updateFinal = false; $oSummariseFinal->run(); $oDal->tally(); // Prepare the dates $olastDateFinal = new Date('2006-03-09 10:59:59'); $oStartDate = new Date(); $oStartDate->copy($olastDateFinal); $oStartDate->addSeconds(1); $oUpdateFinalToDate = new Date('2006-03-09 11:59:59'); // Mock the DAL, and set expectations Mock::generate('OX_Dal_Maintenance_Statistics'); $oDal = new MockOX_Dal_Maintenance_Statistics($this); $oDal->expectOnce('saveSummary', array($oStartDate, $oUpdateFinalToDate, $aTypes, 'data_intermediate_ad', 'data_summary_ad_hourly')); $oServiceLocator->register('OX_Dal_Maintenance_Statistics', $oDal); // Set the controller class $oMaintenanceStatistics = new OX_Maintenance_Statistics(); $oServiceLocator->register('Maintenance_Statistics_Controller', $oMaintenanceStatistics); // Test $oSummariseFinal = new OX_Maintenance_Statistics_Task_SummariseFinal(); $oSummariseFinal->oController->updateIntermediate = false; $oSummariseFinal->oController->updateFinal = true; $oSummariseFinal->oController->oLastDateFinal = $olastDateFinal; $oSummariseFinal->oController->oUpdateFinalToDate = $oUpdateFinalToDate; $oSummariseFinal->run(); $oDal->tally(); // Prepare the dates $olastDateIntermediate = new Date('2006-03-09 10:59:59'); $oStartDate = new Date(); $oStartDate->copy($olastDateIntermediate); $oStartDate->addSeconds(1); $oUpdateIntermediateToDate = new Date('2006-03-09 11:59:59'); $olastDateFinal = new Date('2006-03-09 10:59:59'); $oStartDate = new Date(); $oStartDate->copy($olastDateFinal); $oStartDate->addSeconds(1); $oUpdateFinalToDate = new Date('2006-03-09 11:59:59'); // Mock the DAL, and set expectations Mock::generate('OX_Dal_Maintenance_Statistics'); $oDal = new MockOX_Dal_Maintenance_Statistics($this); $oDal->expectOnce('saveSummary', array($oStartDate, $oUpdateFinalToDate, $aTypes, 'data_intermediate_ad', 'data_summary_ad_hourly')); $oServiceLocator->register('OX_Dal_Maintenance_Statistics', $oDal); // Set the controller class $oMaintenanceStatistics = new OX_Maintenance_Statistics(); $oServiceLocator->register('Maintenance_Statistics_Controller', $oMaintenanceStatistics); // Test $oSummariseFinal = new OX_Maintenance_Statistics_Task_SummariseFinal(); $oSummariseFinal->oController->updateIntermediate = true; $oSummariseFinal->oController->oLastDateIntermediate = $olastDateIntermediate; $oSummariseFinal->oController->oUpdateIntermediateToDate = $oUpdateIntermediateToDate; $oSummariseFinal->oController->updateFinal = true; $oSummariseFinal->oController->oLastDateFinal = $olastDateFinal; $oSummariseFinal->oController->oUpdateFinalToDate = $oUpdateFinalToDate; $oSummariseFinal->run(); $oDal->tally(); }
/** * A method to update the summary table from the intermediate tables. * * @param PEAR::Date $oStartDate The start date/time to update from. * @param PEAR::Date $oEndDate The end date/time to update to. * @param array $aActions An array of data types to summarise. Contains * two array, the first containing the data types, * and the second containing the connection type * values associated with those data types, if * appropriate. For example: * array( * 'types' => array( * 0 => 'request', * 1 => 'impression', * 2 => 'click' * ), * 'connections' => array( * 1 => MAX_CONNECTION_AD_IMPRESSION, * 2 => MAX_CONNECTION_AD_CLICK * ) * ) * Note that the order of the items must match * the order of the items in the database tables * (e.g. in data_intermediate_ad and * data_summary_ad_hourly for the above example). * @param string $fromTable The name of the intermediate table to summarise * from (e.g. 'data_intermediate_ad'). * @param string $toTable The name of the summary table to summarise to * (e.g. 'data_summary_ad_hourly'). */ function saveSummary($oStartDate, $oEndDate, $aActions, $fromTable, $toTable) { $aConf = $GLOBALS['_MAX']['CONF']; // Check that there are types to summarise if (empty($aActions['types']) || empty($aActions['connections'])) { return; } // How many days does the start/end period span? $days = Date_Calc::dateDiff($oStartDate->getDay(), $oStartDate->getMonth(), $oStartDate->getYear(), $oEndDate->getDay(), $oEndDate->getMonth(), $oEndDate->getYear()); if ($days == 0) { // Save the data $this->_saveSummary($oStartDate, $oEndDate, $aActions, $fromTable, $toTable); } else { // Save each day's data separately for ($counter = 0; $counter <= $days; $counter++) { if ($counter == 0) { // This is the first day $oInternalStartDate = new Date(); $oInternalStartDate->copy($oStartDate); $oInternalEndDate = new Date($oStartDate->format('%Y-%m-%d') . ' 23:59:59'); } elseif ($counter == $days) { // This is the last day $oInternalStartDate = new Date($oEndDate->format('%Y-%m-%d') . ' 00:00:00'); $oInternalEndDate = new Date(); $oInternalEndDate->copy($oEndDate); } else { // This is a day in the middle $oDayDate = new Date(); $oDayDate->copy($oStartDate); $oDayDate->addSeconds(SECONDS_PER_DAY * $counter); $oInternalStartDate = new Date($oDayDate->format('%Y-%m-%d') . ' 00:00:00'); $oInternalEndDate = new Date($oDayDate->format('%Y-%m-%d') . ' 23:59:59'); } $this->_saveSummary($oInternalStartDate, $oInternalEndDate, $aActions, $fromTable, $toTable); } } }
/** * A private method to calculate average values when an operation interval * has more than one targeting value. * * @access private * @param array $aValues The array of arrays of values to calculate the * averages from. * @param PEAR::Date $oEndDate The end date/time of the operation interval, * to be used for those values where no expiration * date is set. * @return array The array of "average" values. */ function _calculateAverages($aValues, $oEndDate) { if (empty($aValues) || !is_array($aValues)) { return array(); } reset($aValues); while (list(, $aAdValues) = each($aValues)) { if (empty($aAdValues) || !is_array($aAdValues)) { return array(); } if (count($aAdValues) != 10) { return array(); } } if (empty($oEndDate) || !is_a($oEndDate, 'Date')) { return array(); } $counter = 0; $totalSeconds = 0; $aResult = array('ad_required_impressions' => 0, 'ad_requested_impressions' => 0, 'ad_priority' => 0, 'ad_priority_factor' => 0, 'ad_priority_factor_limited' => 0, 'ad_past_zone_traffic_fraction' => 0, 'average' => true); reset($aValues); while (list(, $aAdValues) = each($aValues)) { if ($counter == 0) { $aResult['interval_start'] = $aAdValues['interval_start']; $aResult['interval_end'] = $aAdValues['interval_end']; } $oCreatedDate = new Date($aAdValues['created']); if (is_null($aAdValues['expired'])) { $oExpiredDate = new Date(); $oExpiredDate->copy($oEndDate); } else { $oExpiredDate = new Date($aAdValues['expired']); } $oSpan = new Date_Span(); $oSpan->setFromDateDiff($oCreatedDate, $oExpiredDate); $seconds = $oSpan->toSeconds(); $aResult['ad_required_impressions'] += $aAdValues['ad_required_impressions'] * $seconds; $aResult['ad_requested_impressions'] += $aAdValues['ad_requested_impressions'] * $seconds; $aResult['ad_priority'] += $aAdValues['ad_priority'] * $seconds; $aResult['ad_priority_factor'] += $aAdValues['ad_priority_factor'] * $seconds; $aResult['ad_past_zone_traffic_fraction'] += $aAdValues['ad_past_zone_traffic_fraction'] * $seconds; if ($aAdValues['ad_priority_factor_limited'] == 1) { $aResult['ad_priority_factor_limited'] = 1; } $counter++; $totalSeconds += $seconds; } $aResult['ad_required_impressions'] /= $totalSeconds; $aResult['ad_requested_impressions'] /= $totalSeconds; $aResult['ad_priority'] /= $totalSeconds; $aResult['ad_priority_factor'] /= $totalSeconds; $aResult['ad_past_zone_traffic_fraction'] /= $totalSeconds; return $aResult; }
/** * The implementation of the OA_Task::run() method that performs * the required task of migrating bucket-based logged data to the * statistics table(s) specified by the appropriate plugin * components. */ function run() { $aConf = $GLOBALS['_MAX']['CONF']; if ($this->oController->updateIntermediate) { // Locate all plugin components which may require bucket data to be // migrated from bucket tables to statistics tables $aSummariseComponents = $this->_locateComponents(); // Are there any components that require data to be migrated? if (empty($aSummariseComponents)) { OA::debug('There are no installed plugins that require data migration', PEAR_LOG_DEBUG); return; } $message = '- Migrating bucket-based logged data to the statistics tables.'; $this->oController->report .= $message . "\n"; // Get the MSE DAL to perform the data migration $oServiceLocator =& OA_ServiceLocator::instance(); $oDal =& $oServiceLocator->get('OX_Dal_Maintenance_Statistics'); // Prepare the "now" date $oNowDate =& $oServiceLocator->get('now'); if (!$oNowDate) { $oNowDate = new Date(); } // Prepare an array of possible start and end dates for the migration, unless they have been set already if (empty($this->aRunDates)) { $this->aRunDates = array(); $oStartDate = new Date(); $oStartDate->copy($this->oController->oLastDateIntermediate); $oStartDate->addSeconds(1); while (Date::compare($oStartDate, $this->oController->oUpdateIntermediateToDate) < 0) { // Calcuate the end of the operation interval $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oStartDate); $oEndDate = new Date(); $oEndDate->copy($aDates['end']); // Store the dates $oStoreStartDate = new Date(); $oStoreStartDate->copy($oStartDate); $oStoreEndDate = new Date(); $oStoreEndDate->copy($oEndDate); $this->aRunDates[] = array('start' => $oStoreStartDate, 'end' => $oStoreEndDate); // Go to the next operation interval $oStartDate->copy($oEndDate); $oStartDate->addSeconds(1); } } // Check to see if any historical raw data needs to be migrated, // post-upgrade, and if so, migrate the data; requires that the // default openXDeliveryLog plugin is installed, so the migration // will not be called if it is not if (key_exists('openXDeliveryLog', $this->aPackages)) { $this->_postUpgrade(); } // Prepare arrays of all of the migration maps of raw migrations $aRunComponents = $this->_prepareMaps($aSummariseComponents, 'raw'); // Run each migration map separately, even if it's for the same table foreach ($aRunComponents as $statisticsTable => $aMaps) { foreach ($aMaps as $componentClassName => $aMigrationDetails) { foreach ($this->aRunDates as $aDates) { $message = "- Migrating raw bucket data from the '{$aMigrationDetails['bucketTable']}' bucket table"; OA::debug($message, PEAR_LOG_DEBUG); $message = " to the '{$statisticsTable}' table, for operation interval range"; OA::debug($message, PEAR_LOG_DEBUG); $message = ' ' . $aDates['start']->format('%Y-%m-%d %H:%M:%S') . ' ' . $aDates['start']->tz->getShortName() . ' to ' . $aDates['end']->format('%Y-%m-%d %H:%M:%S') . ' ' . $aDates['end']->tz->getShortName(); OA::debug($message, PEAR_LOG_DEBUG); $result = $oDal->summariseBucketsRaw($statisticsTable, $aMigrationDetails, $aDates); if (PEAR::isError($result)) { // Oh noz! The bucket data could not be migrated // Tell the user all about it, but then just keep on truckin'... $message = " ERROR: Could not migrate raw bucket data from the '{$aMigrationDetails['bucketTable']}' bucket table"; OA::debug($message, PEAR_LOG_ERR); $message = " Error message was: {$result->message}"; OA::debug($message, PEAR_LOG_ERR); } else { $message = " - Migrated {$result} row(s)"; OA::debug($message, PEAR_LOG_DEBUG); $pruneResult = $aSummariseComponents[$statisticsTable][$componentClassName]->pruneBucket($aDates['end'], $aDates['start']); if (PEAR::isError($pruneResult)) { // Oh noz! The bucket data could not be pruned, and this is // critical - if we can't prune the data, we'll end up double // counting, so exit with a critical error... $message = " ERROR: Could not prune aggregate bucket data from the '" . $aSummariseComponents[$statisticsTable][$componentClassName]->getBucketName() . "' bucket table"; OA::debug($message, PEAR_LOG_CRIT); $message = " Error message was: {$pruneResult->message}"; OA::debug($message, PEAR_LOG_CRIT); $message = " Aborting maintenance execution"; OA::debug($message, PEAR_LOG_CRIT); exit; } else { $message = " - Pruned {$pruneResult} row(s)"; OA::debug($message, PEAR_LOG_DEBUG); } } } } } // Prepare arrays of all of the migration maps of supplementary raw migrations $aRunComponents = $this->_prepareMaps($aSummariseComponents, 'rawSupplementary'); // Run each migration map separately, even if it's for the same table foreach ($aRunComponents as $statisticsTable => $aMaps) { foreach ($aMaps as $componentClassName => $aMigrationDetails) { foreach ($this->aRunDates as $aDates) { $message = "- Migrating supplementary raw bucket data from the '{$aMigrationDetails['bucketTable']}' bucket table"; OA::debug($message, PEAR_LOG_DEBUG); $message = " to the '{$statisticsTable}' table, for operation interval range"; OA::debug($message, PEAR_LOG_DEBUG); $message = ' ' . $aDates['start']->format('%Y-%m-%d %H:%M:%S') . ' ' . $aDates['start']->tz->getShortName() . ' to ' . $aDates['end']->format('%Y-%m-%d %H:%M:%S') . ' ' . $aDates['end']->tz->getShortName(); OA::debug($message, PEAR_LOG_DEBUG); $result = $oDal->summariseBucketsRawSupplementary($statisticsTable, $aMigrationDetails, $aDates); if (PEAR::isError($result)) { // Oh noz! The bucket data could not be migrated // Tell the user all about it, but then just keep on truckin'... $message = " ERROR: Could not migrate supplementary raw bucket data from the '{$aMigrationDetails['bucketTable']}' bucket table"; OA::debug($message, PEAR_LOG_ERR); $message = " Error message was: {$result->message}"; OA::debug($message, PEAR_LOG_ERR); } else { $message = " - Migrated {$result} row(s)"; OA::debug($message, PEAR_LOG_DEBUG); $pruneResult = $aSummariseComponents[$statisticsTable][$componentClassName]->pruneBucket($aDates['end'], $aDates['start']); if (PEAR::isError($pruneResult)) { // Oh noz! The bucket data could not be pruned, and this is // critical - if we can't prune the data, we'll end up double // counting, so exit with a critical error... $message = " ERROR: Could not prune aggregate bucket data from the '" . $aSummariseComponents[$statisticsTable][$componentClassName]->getBucketName() . "' bucket table"; OA::debug($message, PEAR_LOG_CRIT); $message = " Error message was: {$pruneResult->message}"; OA::debug($message, PEAR_LOG_CRIT); $message = " Aborting maintenance execution"; OA::debug($message, PEAR_LOG_CRIT); exit; } else { $message = " - Pruned {$pruneResult} row(s)"; OA::debug($message, PEAR_LOG_DEBUG); } } } } } // Prepare arrays of all of the migration maps of aggregate migrations $aRunComponents = $this->_prepareMaps($aSummariseComponents, 'aggregate'); // Run each migration map by statistics table foreach ($aRunComponents as $statisticsTable => $aMaps) { $aBucketTables = array(); foreach ($aMaps as $aMap) { $aBucketTables[] = $aMap['bucketTable']; } foreach ($this->aRunDates as $aDates) { $aExtras = array(); // Is this the data_intermeidate_ad statistics table? It's special! if ($statisticsTable == $aConf['table']['prefix'] . 'data_intermediate_ad') { $aExtras = array('operation_interval' => $aConf['maintenance']['operationInterval'], 'operation_interval_id' => OX_OperationInterval::convertDateToOperationIntervalID($aDates['start']), 'interval_start' => $oDal->oDbh->quote($aDates['start']->format('%Y-%m-%d %H:%M:%S'), 'timestamp') . $oDal->timestampCastString, 'interval_end' => $oDal->oDbh->quote($aDates['end']->format('%Y-%m-%d %H:%M:%S'), 'timestamp') . $oDal->timestampCastString, 'creative_id' => 0, 'updated' => $oDal->oDbh->quote($oNowDate->format('%Y-%m-%d %H:%M:%S'), 'timestamp') . $oDal->timestampCastString); } $message = "- Migrating aggregate bucket data from the '" . implode("', '", $aBucketTables) . "' bucket table(s)"; OA::debug($message, PEAR_LOG_DEBUG); $message = " to the '{$statisticsTable}' table, for operation interval range"; OA::debug($message, PEAR_LOG_DEBUG); $message = ' ' . $aDates['start']->format('%Y-%m-%d %H:%M:%S') . ' ' . $aDates['start']->tz->getShortName() . ' to ' . $aDates['end']->format('%Y-%m-%d %H:%M:%S') . ' ' . $aDates['end']->tz->getShortName(); OA::debug($message, PEAR_LOG_DEBUG); $result = $oDal->summariseBucketsAggregate($statisticsTable, $aMaps, $aDates, $aExtras); if (PEAR::isError($result)) { // Oh noz! The bucket data could not be migrated // Tell the user all about it, but then just keep on truckin'... $message = " ERROR: Could not migrate aggregate bucket data from the '" . implode("', '", $aBucketTables) . "' bucket table(s)"; OA::debug($message, PEAR_LOG_ERR); $message = " Error message was: {$result->message}"; OA::debug($message, PEAR_LOG_ERR); } else { $message = " - Migrated {$result} row(s)"; OA::debug($message, PEAR_LOG_DEBUG); foreach ($aMaps as $componentClassName => $aMap) { $pruneResult = $aSummariseComponents[$statisticsTable][$componentClassName]->pruneBucket($aDates['end'], $aDates['start']); if (PEAR::isError($pruneResult)) { // Oh noz! The bucket data could not be pruned, and this is // critical - if we can't prune the data, we'll end up double // counting, so exit with a critical error... $message = " ERROR: Could not prune aggregate bucket data from the '" . $aSummariseComponents[$statisticsTable][$componentClassName]->getBucketName() . "' bucket table"; OA::debug($message, PEAR_LOG_CRIT); $message = " Error message was: {$pruneResult->message}"; OA::debug($message, PEAR_LOG_CRIT); $message = " Aborting maintenance execution"; OA::debug($message, PEAR_LOG_CRIT); exit; } else { $message = " - Pruned {$pruneResult} row(s)"; OA::debug($message, PEAR_LOG_DEBUG); } } } } } // Prepare arrays of all of the migration maps of custom migrations // (If we refactor stats this will be the one and only method.) $aRunComponents = $this->_prepareMaps($aSummariseComponents, 'custom'); // Run each migration map by statistics table foreach ($aRunComponents as $statisticsTable => $aMaps) { $aBucketTables = array(); foreach ($aMaps as $aMap) { $aBucketTables[] = $aMap['bucketTable']; } foreach ($this->aRunDates as $aDates) { $aExtras = array(); $message = "- Migrating aggregate bucket data from the '" . implode("', '", $aBucketTables) . "' bucket table(s)"; OA::debug($message, PEAR_LOG_DEBUG); $message = " to the '{$statisticsTable}' table, for operation interval range"; OA::debug($message, PEAR_LOG_DEBUG); $message = ' ' . $aDates['start']->format('%Y-%m%d %H:%M:%S') . ' ' . $aDates['start']->tz->getShortName() . ' to ' . $aDates['end']->format('%Y-%m%d %H:%M:%S') . ' ' . $aDates['end']->tz->getShortName(); OA::debug($message, PEAR_LOG_DEBUG); // Call the components migrateStats method. foreach ($aMaps as $componentClassName => $aMap) { $result = $aSummariseComponents[$statisticsTable][$componentClassName]->migrateStatistics($aDates['end']); if (PEAR::isError($result)) { // Oh noz! The bucket data could not be migrated // Tell the user all about it, but then just keep on truckin'... $message = " ERROR: Could not migrate aggregate bucket data from the '" . implode("', '", $aBucketTables) . "' bucket table(s)"; OA::debug($message, PEAR_LOG_ERR); $message = " Error message was: {$result->message}."; OA::debug($message, PEAR_LOG_ERR); } else { // Only prune the bucket if we migrated the stats successfully. $aSummariseComponents[$statisticsTable][$componentClassName]->pruneBucket($aDates['end'], $aDates['start']); } } } } } $this->aRunDates = array(); }
/** * A method to return the forecast impressions for a zone, indexed by operation interval, * from the current operation interval through the past week. If no forecast stored in * the database for a given OI, uses average of forecasts found. * * @param integer $zoneId The Zone ID. * @return mixed An array on success, false on failure. The array is of the format: * array( * [operation_interval_id] => array( * ['zone_id'] => zone_id, * ['_impressions'] => forecast_impressions, * ['operation_interval_id'] => operation_interval_id * ) * [operation_interval_id] => array( * ['zone_id'] => zone_id, * ['forecast_impressions'] => forecast_impressions, * ['operation_interval_id'] => operation_interval_id * ) * . * . * . * ) */ function getPreviousWeekZoneForcastImpressions($zoneId) { if (empty($zoneId) || !is_numeric($zoneId)) { OA::debug('Invalid zone ID argument', PEAR_LOG_ERR); return false; } $aConf = $GLOBALS['_MAX']['CONF']; $oServiceLocator =& OA_ServiceLocator::instance(); $oDate =& $oServiceLocator->get('now'); if (!$oDate) { return false; } // Get previous OI $oPreviousOI = new Date($oDate); $oPreviousOI->subtractSeconds(OX_OperationInterval::getOperationInterval() * 60); // Get the start and end ranges of the current week, up to the previous OI $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oPreviousOI); $oDateWeekStart = new Date(); $oDateWeekStart->copy($aDates['end']); $oDateWeekStart->subtractSeconds(SECONDS_PER_WEEK - 1); $oDateWeekEnd = new Date(); $oDateWeekEnd->copy($aDates['end']); // Select the zone forecasts from the database $tableName = $this->_getTablename('data_intermediate_ad'); $oneHourInterval = OA_Dal::quoteInterval(1, 'hour'); $query = "\n SELECT\n SUM(impressions) AS forecast_impressions,\n operation_interval_id AS operation_interval_id,\n interval_start AS interval_start,\n interval_end AS interval_end\n FROM\n {$tableName}\n WHERE\n zone_id = {$zoneId}\n AND operation_interval = {$aConf['maintenance']['operationInterval']}\n AND interval_start >= '" . $oDateWeekStart->format('%Y-%m-%d %H:%M:%S') . "'\n AND interval_end <= '" . $oDateWeekEnd->format('%Y-%m-%d %H:%M:%S') . "'\n AND date_time > DATE_SUB('" . $oDateWeekStart->format('%Y-%m-%d %H:%M:%S') . "', {$oneHourInterval})\n AND date_time < DATE_ADD('" . $oDateWeekEnd->format('%Y-%m-%d %H:%M:%S') . "', {$oneHourInterval})\n AND zone_id != 0\n GROUP BY\n \tinterval_start,\n \tinterval_end,\n \toperation_interval_id\n ORDER BY\n interval_start"; $rc = $this->oDbh->query($query); $totalForecastImpressions = 0; $count = 0; if (!PEAR::isError($rc)) { // Sort the results into an array indexed by the operation interval ID $aFinalResult = array(); while ($aRow = $rc->fetchRow()) { $aFinalResult[$aRow['operation_interval_id']] = array('zone_id' => $zoneId, 'forecast_impressions' => $aRow['forecast_impressions'], 'operation_interval_id' => $aRow['operation_interval_id']); $count++; $totalForecastImpressions += $aRow['forecast_impressions']; } } $averageForecastImpressions = 0; if ($count > 0) { $averageForecastImpressions = floor($totalForecastImpressions / $count); } if ($averageForecastImpressions == 0) { $averageForecastImpressions = $this->getZoneForecastDefaultZoneImpressions(); } // Check each operation interval ID has a forecast impression value, // and if not, set to the system default. for ($operationIntervalID = 0; $operationIntervalID < OX_OperationInterval::operationIntervalsPerWeek(); $operationIntervalID++) { if (!isset($aFinalResult[$operationIntervalID])) { $aFinalResult[$operationIntervalID] = array('zone_id' => $zoneId, 'forecast_impressions' => $averageForecastImpressions, 'operation_interval_id' => $operationIntervalID); } } // Overwrite current OI with previous OI to match the zone forecasting algorithm $currOI = OX_OperationInterval::convertDateToOperationIntervalID($oDate); $prevOI = OX_OperationInterval::previousOperationIntervalID($currOI); $aFinalResult[$currOI]['forecast_impressions'] = $aFinalResult[$prevOI]['forecast_impressions']; // Return data return $aFinalResult; }
/** * A method to return an array containing the days in the span, including the start * and end days, where each day in the array is formatted as a string. * * @param string $format An optional PEAR::Date compatible format string. * @return array An array of the days in the span. */ function getDayArray($format = '%Y-%m-%d') { $aDays = array(); $oDate = new Date(); $oDate->copy($this->oStartDate); while (!$oDate->after($this->oEndDate)) { $aDays[] = $oDate->format($format); $oDate->addSeconds(SECONDS_PER_DAY); } return $aDays; }
/** * A private method to calculate an equivalent "last time that maintenance * statistics was run" value from logged delivery data, if possible. * * Enables the MSE process to be kick-started for new installations, where * the MSE has not been run before; but without causing the MSE to run * until the installation is actually logging data. * * @access private * @param integer $type The update type that "occurred" - that is, * OX_DAL_MAINTENANCE_STATISTICS_UPDATE_OI if the required * calculated "update date" needs to be in terms of the * operation interval; or * OX_DAL_MAINTENANCE_STATISTICS_UPDATE_HOUR if the * required calculated "update date" needs to be in terms * of the hour. * @return Date A Date representing the end of the operation interval * which is before the date found of the earliest known * logged delivery data record. Returns null if no logged * delivery data can be located. */ function _getEarliestLoggedDeliveryData($type) { // Obtain all components from the deliveryLog plugin group $aDeliveryLogComponents = OX_Component::getComponents('deliveryLog'); // Are there any components? if (empty($aDeliveryLogComponents)) { return null; } // Call the "getEarliestLoggedDataDate()" method on each // component, to find out what is the date of the earliest // logged data that the component knows about $aResult = OX_Component::callOnComponents($aDeliveryLogComponents, 'getEarliestLoggedDataDate'); if ($aResults === false) { return null; } // Iterate over the results from above, and see if any of // the components returned valid dates, and if so, which // of the results is the earliest $oDate = null; foreach ($aResult as $oComponentDate) { if (is_a($oComponentDate, 'Date')) { // Logged data was located! Is this date earlier than // any previous "earliest" logged delivery data? if (is_null($oDate)) { $oDate = new Date(); $oDate->copy($oComponentDate); } else { if ($oComponentDate->before($oDate)) { $oDate->copy($oComponentDate); } } } } // Was a date found? if (is_null($oDate) || !is_a($oDate, 'Date')) { return null; } // Convert the located earliest logged data date into either the // end of the previous operation interval, or the end of the previous // hour, depending on the required type if ($type == OX_DAL_MAINTENANCE_STATISTICS_UPDATE_OI) { $aDates = OX_OperationInterval::convertDateToPreviousOperationIntervalStartAndEndDates($oDate); } else { $aDates = OX_OperationInterval::convertDateToPreviousOperationIntervalStartAndEndDates($oDate, 60); } // Return the date return $aDates['end']; }
/** * A method to return the forcast impressions for a zone, indexed by operation interval, * from the current operation interval through the past week. If no forecast stored in * the database, uses the defualt value from the configuration file. * * @param integer $zoneId The Zone ID. * @return mixed An array on success, false on failure. The array is of the format: * array( * [operation_interval_id] => array( * ['zone_id'] => zone_id, * ['forecast_impressions'] => forecast_impressions, * ['operation_interval_id'] => operation_interval_id * ) * [operation_interval_id] => array( * ['zone_id'] => zone_id, * ['forecast_impressions'] => forecast_impressions, * ['operation_interval_id'] => operation_interval_id * ) * . * . * . * ) */ function getPreviousWeekZoneForcastImpressions($zoneId) { if (empty($zoneId) || !is_numeric($zoneId)) { OA::debug('Invalid zone ID argument', PEAR_LOG_ERR); return false; } $aConf = $GLOBALS['_MAX']['CONF']; $oServiceLocator =& OA_ServiceLocator::instance(); $oDate =& $oServiceLocator->get('now'); if (!$oDate) { return false; } // Get the start and end ranges of the current week $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oDate); $oDateWeekStart = new Date(); $oDateWeekStart->copy($aDates['end']); $oDateWeekStart->subtractSeconds(SECONDS_PER_WEEK - 1); $oDateWeekEnd = new Date(); $oDateWeekEnd->copy($aDates['end']); // Select the zone forecasts from the database $tableName = $this->_getTablename('data_summary_zone_impression_history'); $query = "\n SELECT\n zone_id AS zone_id,\n forecast_impressions AS forecast_impressions,\n operation_interval_id AS operation_interval_id,\n interval_start AS interval_start,\n interval_end AS interval_end\n FROM\n {$tableName}\n WHERE\n zone_id = {$zoneId}\n AND operation_interval = {$aConf['maintenance']['operationInterval']}\n AND interval_start >= '" . $oDateWeekStart->format('%Y-%m-%d %H:%M:%S') . "'\n AND interval_end <= '" . $oDateWeekEnd->format('%Y-%m-%d %H:%M:%S') . "'\n AND zone_id != 0\n ORDER BY\n interval_start"; $rc = $this->oDbh->query($query); if (!PEAR::isError($rc)) { // Sort the results into an array indexed by the operation interval ID $aFinalResult = array(); while ($aRow = $rc->fetchRow()) { $aFinalResult[$aRow['operation_interval_id']] = array('zone_id' => $aRow['zone_id'], 'forecast_impressions' => $aRow['forecast_impressions'], 'operation_interval_id' => $aRow['operation_interval_id']); } } // Check each operation interval ID has a forecast impression value, // and if not, set to the system default. for ($operationIntervalID = 0; $operationIntervalID < OX_OperationInterval::operationIntervalsPerWeek(); $operationIntervalID++) { if (!isset($aFinalResult[$operationIntervalID])) { $aFinalResult[$operationIntervalID] = array('zone_id' => $zoneId, 'forecast_impressions' => ZONE_FORECAST_DEFAULT_ZONE_IMPRESSIONS, 'operation_interval_id' => $operationIntervalID); } } return $aFinalResult; }
/** * @param $oDate * @param $campaignId * @return int Number of emails sent */ function sendCampaignImpendingExpiryEmail($oDate, $campaignId) { $aConf = $GLOBALS['_MAX']['CONF']; global $date_format; $oPreference = new OA_Preferences(); if (!isset($this->aAdminCache)) { // Get admin account ID $adminAccountId = OA_Dal_ApplicationVariables::get('admin_account_id'); // Get admin prefs $adminPrefsNames = $this->_createPrefsListPerAccount(OA_ACCOUNT_ADMIN); $aAdminPrefs = $oPreference->loadAccountPreferences($adminAccountId, $adminPrefsNames, OA_ACCOUNT_ADMIN); // Get admin users $aAdminUsers = $this->getAdminUsersLinkedToAccount(); // Store admin cache $this->aAdminCache = array($aAdminPrefs, $aAdminUsers); } else { // Retrieve admin cache list($aAdminPrefs, $aAdminUsers) = $this->aAdminCache; } $aPreviousOIDates = OX_OperationInterval::convertDateToPreviousOperationIntervalStartAndEndDates($oDate); $aPreviousOIDates = OX_OperationInterval::convertDateToPreviousOperationIntervalStartAndEndDates($aPreviousOIDates['start']); $doCampaigns = OA_Dal::staticGetDO('campaigns', $campaignId); if (!$doCampaigns) { return 0; } $aCampaign = $doCampaigns->toArray(); if (!isset($this->aClientCache[$aCampaign['clientid']])) { $doClients = OA_Dal::staticGetDO('clients', $aCampaign['clientid']); // Add advertiser linked users $aLinkedUsers['advertiser'] = $this->getUsersLinkedToAccount('clients', $aCampaign['clientid']); // Add advertiser prefs $advertiserPrefsNames = $this->_createPrefsListPerAccount(OA_ACCOUNT_ADVERTISER); $aPrefs['advertiser'] = $oPreference->loadAccountPreferences($doClients->account_id, $advertiserPrefsNames, OA_ACCOUNT_ADVERTISER); if (!isset($aAgencyCache[$doClients->agencyid])) { // Add manager linked users $doAgency = OA_Dal::staticGetDO('agency', $doClients->agencyid); $aLinkedUsers['manager'] = $this->getUsersLinkedToAccount('agency', $doClients->agencyid); // Add manager preferences $managerPrefsNames = $this->_createPrefsListPerAccount(OA_ACCOUNT_MANAGER); $aPrefs['manager'] = $oPreference->loadAccountPreferences($doAgency->account_id, $managerPrefsNames, OA_ACCOUNT_MANAGER); // Get agency "From" details $aAgencyFromDetails = $this->_getAgencyFromDetails($doAgency->agencyid); // Store in the agency cache $this->aAgencyCache = array($doClients->agencyid => array($aLinkedUsers['manager'], $aPrefs['manager'], $aAgencyFromDetails)); } else { // Retrieve agency cache list($aLinkedUsers['manager'], $aPrefs['manager'], $aAgencyFromDetails) = $this->aAgencyCache[$doClients->agencyid]; } // Add admin linked users and preferences $aLinkedUsers['admin'] = $aAdminUsers; $aPrefs['admin'] = $aAdminPrefs; // Create a linked user 'special' for the advertiser that will take the admin preferences for advertiser $aLinkedUsers['special']['advertiser'] = $doClients->toArray(); $aLinkedUsers['special']['advertiser']['contact_name'] = $aLinkedUsers['special']['advertiser']['contact']; $aLinkedUsers['special']['advertiser']['email_address'] = $aLinkedUsers['special']['advertiser']['email']; $aLinkedUsers['special']['advertiser']['language'] = ''; $aLinkedUsers['special']['advertiser']['user_id'] = 0; // Check that every user is not going to receive more than one email if they // are linked to more than one account $aLinkedUsers = $this->_deleteDuplicatedUser($aLinkedUsers); // Create the linked special user preferences from the admin preferences // the special user is the client that doesn't have preferences in the database $aPrefs['special'] = $aPrefs['admin']; $aPrefs['special']['warn_email_special'] = $aPrefs['special']['warn_email_advertiser']; $aPrefs['special']['warn_email_special_day_limit'] = $aPrefs['special']['warn_email_advertiser_day_limit']; $aPrefs['special']['warn_email_special_impression_limit'] = $aPrefs['special']['warn_email_advertiser_impression_limit']; // Store in the client cache $this->aClientCache = array($aCampaign['clientid'] => array($aLinkedUsers, $aPrefs, $aAgencyFromDetails)); } else { // Retrieve client cache list($aLinkedUsers, $aPrefs, $aAgencyFromDetails) = $this->aClientCache[$aCampaign['clientid']]; } $copiesSent = 0; foreach ($aLinkedUsers as $accountType => $aUsers) { if ($accountType == 'special' || $accountType == 'advertiser') { // Get the agency details and use them for emailing advertisers $aFromDetails = $aAgencyFromDetails; } else { // Use the Admin details $aFromDetails = ''; } if ($aPrefs[$accountType]['warn_email_' . $accountType]) { // Does the account type want warnings when the impressions are low? if ($aPrefs[$accountType]['warn_email_' . $accountType . '_impression_limit'] > 0 && $aCampaign['views'] > 0) { // Test to see if the placements impressions remaining are less than the limit $dalCampaigns = OA_Dal::factoryDAL('campaigns'); $remainingImpressions = $dalCampaigns->getAdImpressionsLeft($aCampaign['campaignid']); if ($remainingImpressions < $aPrefs[$accountType]['warn_email_' . $accountType . '_impression_limit']) { // Yes, the placement will expire soon! But did the placement just reach // the point where it is about to expire, or did it happen a while ago? $previousRemainingImpressions = $dalCampaigns->getAdImpressionsLeft($aCampaign['campaignid'], $aPreviousOIDates['end']); if ($previousRemainingImpressions >= $aPrefs[$accountType]['warn_email_' . $accountType . '_impression_limit']) { // Yes! This is the operation interval that the boundary // was crossed to the point where it's about to expire, // so send that email, baby! foreach ($aUsers as $aUser) { $aEmail = $this->prepareCampaignImpendingExpiryEmail($aUser, $aCampaign['clientid'], $aCampaign['campaignid'], 'impressions', $aPrefs[$accountType]['warn_email_' . $accountType . '_impression_limit'], $accountType); if ($aEmail !== false) { if ($this->sendMail($aEmail['subject'], $aEmail['contents'], $aUser['email_address'], $aUser['contact_name'], $aFromDetails)) { $copiesSent++; if ($aConf['email']['logOutgoing']) { phpAds_userlogSetUser(phpAds_userMaintenance); phpAds_userlogAdd(phpAds_actionWarningMailed, $aPlacement['campaignid'], "{$aEmail['subject']}\n\n\n {$aUser['contact_name']}({$aUser['email_address']})\n\n\n {$aEmail['contents']}"); } } } } } } } // Does the account type want warnings when the days are low? if ($aPrefs[$accountType]['warn_email_' . $accountType . '_day_limit'] > 0 && !empty($aCampaign['expire_time'])) { // Calculate the date that should be used to see if the warning needs to be sent $warnSeconds = (int) ($aPrefs[$accountType]['warn_email_' . $accountType . '_day_limit'] + 1) * SECONDS_PER_DAY; $oEndDate = new Date($aCampaign['expire_time']); $oEndDate->setTZbyID('UTC'); $oTestDate = new Date(); $oTestDate->copy($oDate); $oTestDate->addSeconds($warnSeconds); // Test to see if the test date is after the placement's expiration date if ($oTestDate->after($oEndDate)) { // Yes, the placement will expire soon! But did the placement just reach // the point where it is about to expire, or did it happen a while ago? $oiSeconds = (int) $aConf['maintenance']['operationInterval'] * 60; $oTestDate->subtractSeconds($oiSeconds); if (!$oTestDate->after($oEndDate)) { // Yes! This is the operation interval that the boundary // was crossed to the point where it's about to expire, // so send those emails, baby! foreach ($aUsers as $aUser) { $aEmail = $this->prepareCampaignImpendingExpiryEmail($aUser, $aCampaign['clientid'], $aCampaign['campaignid'], 'date', $oEndDate->format($date_format), $accountType); if ($aEmail !== false) { if ($this->sendMail($aEmail['subject'], $aEmail['contents'], $aUser['email_address'], $aUser['contact_name'], $aFromDetails)) { $copiesSent++; if ($aConf['email']['logOutgoing']) { phpAds_userlogSetUser(phpAds_userMaintenance); phpAds_userlogAdd(phpAds_actionWarningMailed, $aPlacement['campaignid'], "{$aEmail['subject']}\n\n\n {$aUser['contact_name']}({$aUser['email_address']})\n\n\n {$aEmail['contents']}"); } } } } } } } } } // Restore the default language strings Language_Loader::load('default'); return $copiesSent; }
/** * A method to test the MAX_Delivery_log_logConversion() function. */ function test_MAX_Delivery_log_logConversion() { $aConf =& $GLOBALS['_MAX']['CONF']; $aConf['maintenance']['operationInterval'] = 60; $GLOBALS['_MAX']['NOW'] = time(); $oNowDate = new Date($GLOBALS['_MAX']['NOW']); $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oNowDate); $intervalStart = $aDates['start']->format('%Y-%m-%d %H:%M:%S'); $oConversionDate = new Date(); $oConversionDate->copy($oNowDate); $oConversionDate->subtractSeconds(60); $_SERVER['REMOTE_ADDR'] = '127.0.0.99'; // Test to ensure that the openXDeliveryLog plugin's data bucket // table does not exist $oTable = new OA_DB_Table(); $tableExists = $oTable->extistsTable($aConf['table']['prefix'] . 'data_bkt_a'); $this->assertFalse($tableExists); // Test calling the main logging function without any plugins installed, // to ensure that this does not result in any kind of error $aConversion = array('action_type' => MAX_CONNECTION_AD_CLICK, 'tracker_type' => MAX_CONNECTION_TYPE_SALE, 'status' => MAX_CONNECTION_STATUS_APPROVED, 'cid' => 2, 'zid' => 3, 'dt' => $GLOBALS['_MAX']['NOW'] - 60, 'window' => 60); MAX_Delivery_log_logConversion(1, $aConversion); // Install the openXDeliveryLog plugin TestEnv::installPluginPackage('openXDeliveryLog', false); // Test to ensure that the openXDeliveryLog plugin's data bucket // table now does exist $tableExists = $oTable->extistsTable($aConf['table']['prefix'] . 'data_bkt_a'); $this->assertTrue($tableExists); // Ensure that there are is nothing logged in the data bucket table $doData_bkt_a = OA_Dal::factoryDO('data_bkt_a'); $doData_bkt_a->find(); $rows = $doData_bkt_a->getRowCount(); $this->assertEqual($rows, 0); // Call the conversion logging function $aConversionInfo = MAX_Delivery_log_logConversion(1, $aConversion); // Ensure that the data was logged correctly $doData_bkt_a = OA_Dal::factoryDO('data_bkt_a'); $doData_bkt_a->find(); $rows = $doData_bkt_a->getRowCount(); $this->assertEqual($rows, 1); $doData_bkt_a = OA_Dal::factoryDO('data_bkt_a'); $doData_bkt_a->server_conv_id = 1; $doData_bkt_a->find(); $rows = $doData_bkt_a->getRowCount(); $this->assertEqual($rows, 1); $doData_bkt_a->fetch(); $this->assertEqual($doData_bkt_a->server_ip, 'singleDB'); $this->assertEqual($doData_bkt_a->tracker_id, 1); $this->assertEqual($doData_bkt_a->date_time, $oNowDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($doData_bkt_a->action_date_time, $oConversionDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($doData_bkt_a->creative_id, 2); $this->assertEqual($doData_bkt_a->zone_id, 3); $this->assertEqual($doData_bkt_a->ip_address, '127.0.0.99'); $this->assertEqual($doData_bkt_a->action, MAX_CONNECTION_AD_CLICK); $this->assertEqual($doData_bkt_a->window, 60); $this->assertEqual($doData_bkt_a->status, MAX_CONNECTION_STATUS_APPROVED); $this->assertTrue(is_array($aConversionInfo)); $this->assertTrue(is_array($aConversionInfo['deliveryLog:oxLogConversion:logConversion'])); $this->assertEqual($aConversionInfo['deliveryLog:oxLogConversion:logConversion']['server_conv_id'], 1); $this->assertEqual($aConversionInfo['deliveryLog:oxLogConversion:logConversion']['server_raw_ip'], 'singleDB'); $aConversion['cid'] = 5; // Call the conversion logging function $aConversionInfo = MAX_Delivery_log_logConversion(1, $aConversion); // Ensure that the data was logged correctly $doData_bkt_a = OA_Dal::factoryDO('data_bkt_a'); $doData_bkt_a->find(); $rows = $doData_bkt_a->getRowCount(); $this->assertEqual($rows, 2); $doData_bkt_a = OA_Dal::factoryDO('data_bkt_a'); $doData_bkt_a->server_conv_id = 1; $doData_bkt_a->find(); $rows = $doData_bkt_a->getRowCount(); $this->assertEqual($rows, 1); $doData_bkt_a->fetch(); $this->assertEqual($doData_bkt_a->server_ip, 'singleDB'); $this->assertEqual($doData_bkt_a->tracker_id, 1); $this->assertEqual($doData_bkt_a->date_time, $oNowDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($doData_bkt_a->action_date_time, $oConversionDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($doData_bkt_a->creative_id, 2); $this->assertEqual($doData_bkt_a->zone_id, 3); $this->assertEqual($doData_bkt_a->ip_address, '127.0.0.99'); $this->assertEqual($doData_bkt_a->action, MAX_CONNECTION_AD_CLICK); $this->assertEqual($doData_bkt_a->window, 60); $this->assertEqual($doData_bkt_a->status, MAX_CONNECTION_STATUS_APPROVED); $doData_bkt_a = OA_Dal::factoryDO('data_bkt_a'); $doData_bkt_a->server_conv_id = 2; $doData_bkt_a->find(); $rows = $doData_bkt_a->getRowCount(); $this->assertEqual($rows, 1); $doData_bkt_a->fetch(); $this->assertEqual($doData_bkt_a->server_ip, 'singleDB'); $this->assertEqual($doData_bkt_a->tracker_id, 1); $this->assertEqual($doData_bkt_a->date_time, $oNowDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($doData_bkt_a->action_date_time, $oConversionDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($doData_bkt_a->creative_id, 5); $this->assertEqual($doData_bkt_a->zone_id, 3); $this->assertEqual($doData_bkt_a->ip_address, '127.0.0.99'); $this->assertEqual($doData_bkt_a->action, MAX_CONNECTION_AD_CLICK); $this->assertEqual($doData_bkt_a->window, 60); $this->assertEqual($doData_bkt_a->status, MAX_CONNECTION_STATUS_APPROVED); $this->assertTrue(is_array($aConversionInfo)); $this->assertTrue(is_array($aConversionInfo['deliveryLog:oxLogConversion:logConversion'])); $this->assertEqual($aConversionInfo['deliveryLog:oxLogConversion:logConversion']['server_conv_id'], 2); $this->assertEqual($aConversionInfo['deliveryLog:oxLogConversion:logConversion']['server_raw_ip'], 'singleDB'); // Uninstall the openXDeliveryLog plugin TestEnv::uninstallPluginPackage('openXDeliveryLog', false); // Restore the test configuration file TestEnv::restoreConfig(); }
/** * A method to calculate the range of dates that a statistics screen needs to display. * * Returns an array of values where: * * - If "week" or "day" is the breakdown, array is of days, indexed by "YYYY-MM-DD", * and formatted using the user's local format for days. * * - If "month" is the breakdown, array is of months, indexed by "YYYY-MM", * and formatted using the user's local format for months and days. * * - If "dow" is the breakdown, array is of days of the week, indexed by the integers * 0 to 6, and formatted with the user's local weekday names. * * - If "hour" is the breakdown, array is of hours of the day, indexed by the integers * 0 to 23, and formatted in the format "00:00 - 00:59", "01:00 01:59", etc. * * @param array $aDates An array of the start and end dates in use by the day * span selector element, if set. * @param string $breakdown The breakdown type in use. One of "week", "day", "month", * "dow" or "hour". * @param PEAR::Date $oStatsStartDate A date object representing the first day of statistics * that are available. * @return array The array, as described above. */ function getDatesArray($aDates, $breakdown, $oStatsStartDate) { // Does the day span selector element have dates set? if ($aDates['day_begin'] && $aDates['day_end'] || $aDates['period_start'] && $aDates['period_end']) { if ($aDates['day_begin'] && $aDates['day_end']) { // Use the dates given by the day span selector element $oStartDate = new Date($aDates['day_begin']); $oEndDate = new Date($aDates['day_end']); } else { // Use the dates given by the period_start and period_end $oStartDate = new Date($aDates['period_start']); $oEndDate = new Date($aDates['period_end']); } // Adjust end date to be now, if it's in the future if ($oEndDate->isFuture()) { $oEndDate = new Date(); $aDates['day_end'] = new Date(); $aDates['day_end'] = $aDates['day_end']->format('%Y-%m-%d'); } } else { // Use the dates given by the statistics date limitation // and now $oStartDate = new Date(); $oStartDate->copy($oStatsStartDate); $oEndDate = new Date(); } // Prepare the return array $aDatesResult = array(); switch ($breakdown) { case 'week': case 'day': $oOneDaySpan = new Date_Span('1', '%d'); $oEndDate->addSpan($oOneDaySpan); $oDate = new Date(); $oDate->copy($oStartDate); while ($oDate->before($oEndDate)) { $aDatesResult[$oDate->format('%Y-%m-%d')] = $oDate->format($GLOBALS['date_format']); $oDate->addSpan($oOneDaySpan); } break; case 'month': $oOneMonthSpan = new Date_Span((string) ($oEndDate->getDaysInMonth() - $oEndDate->getDay() + 1), '%d'); $oEndDate->addSpan($oOneMonthSpan); $oDate = new Date(); $oDate->copy($oStartDate); while ($oDate->before($oEndDate)) { $aDatesResult[$oDate->format('%Y-%m')] = $oDate->format($GLOBALS['month_format']); $oOneMonthSpan = new Date_Span((string) ($oDate->getDaysInMonth() - $oDate->getDay() + 1), '%d'); $oDate->addSpan($oOneMonthSpan); } break; case 'dow': for ($dow = 0; $dow < 7; $dow++) { $aDatesResult[$dow] = $GLOBALS['strDayFullNames'][$dow]; } break; case 'hour': for ($hour = 0; $hour < 24; $hour++) { $aDatesResult[$hour] = sprintf('%02d:00 - %02d:59', $hour, $hour); } break; } return $aDatesResult; }
/** * A private method to run the "midnight" general pruning tasks. * * @access private */ function _runGeneralPruning() { if (empty($GLOBALS['_MAX']['CONF']['maintenance']['pruneDataTables'])) { return; } // Calculate the date before which it is valid to prune data $oServiceLocator =& OA_ServiceLocator::instance(); $oNowDate =& $oServiceLocator->get('now'); if (is_null($oNowDate) || !is_a($oNowDate, 'Date')) { return; } $oPruneDate = new Date(); $oPruneDate->copy($oNowDate); $oPruneDate->subtractSeconds(OA_MAINTENANCE_FIXED_PRUNING * SECONDS_PER_DAY); $oFormattedPruneDate = $this->oDbh->quote($oPruneDate->format('%Y-%m-%d %H:%M:%S'), 'timestamp'); $oFormattedPruneTimestamp = $this->oDbh->quote($oPruneDate->getTime(), 'integer'); // Prune old data from the log_maintenance_statistics table $doLog_maintenance_statistics = OA_Dal::factoryDO('log_maintenance_statistics'); $doLog_maintenance_statistics->whereAdd("start_run < {$oFormattedPruneDate}"); $doLog_maintenance_statistics->delete(true); // Prune old data from the log_maintenance_priority table $doLog_maintenance_priority = OA_Dal::factoryDO('log_maintenance_priority'); $doLog_maintenance_priority->whereAdd("start_run < {$oFormattedPruneDate}"); $doLog_maintenance_priority->delete(true); // Prune old data from the userlog table $doUserlog = OA_Dal::factoryDO('userlog'); $doUserlog->whereAdd("timestamp < {$oFormattedPruneTimestamp}"); $doUserlog->delete(true); }
/** * Compares two dates * * Compares two dates. Suitable for use * in sorting functions. * * @access public * @param object Date $xd1 the first date * @param object Date $xd2 the second date * @return int 0 if the dates are equal, -1 if d1 is before d2, 1 if d1 is after d2 */ function compare($xd1, $xd2) { $d1 = new Date(); $d1->copy($xd1); $d2 = new Date(); $d2->copy($xd2); $d1->convertTZ(new Date_TimeZone('UTC')); $d2->convertTZ(new Date_TimeZone('UTC')); $days1 = Date_Calc::dateToDays($d1->day, $d1->month, $d1->year); $days2 = Date_Calc::dateToDays($d2->day, $d2->month, $d2->year); if ($days1 < $days2) { return -1; } if ($days1 > $days2) { return 1; } if ($d1->hour < $d2->hour) { return -1; } if ($d1->hour > $d2->hour) { return 1; } if ($d1->minute < $d2->minute) { return -1; } if ($d1->minute > $d2->minute) { return 1; } if ($d1->second < $d2->second) { return -1; } if ($d1->second > $d2->second) { return 1; } return 0; }
/** * A method to determine if the delivery limitation stored will prevent an * ad from delivering or not, given a time/date. * * @abstract * @param object $oDate PEAR:Date, represeting the time/date to test if the ACL would * block delivery at that point in time. * @return mixed A boolean (true if the ad is BLOCKED (i.e. will NOT deliver), false * if the ad is NOT BLOCKED (i.e. WILL deliver), or a PEAR::Error. */ function deliveryBlocked($oDate) { if (!is_a($oDate, 'Date')) { return MAX::raiseError('Parameter passed to OA_Maintenance_Priority_DeliveryLimitation_Date is not a PEAR::Date object', MAX_ERROR_INVALIDARGS); } // Clone the date $oCloneDate = new Date(); $oCloneDate->copy($oDate); // Reset time part of date $oCloneDate->setHour(0); $oCloneDate->setMinute(0); $oCloneDate->setSecond(0); // 0 if the dates are equal; // -1 if $oCloneDate is before $this->date; // 1 if $oCloneDate is after $this->date $val = Date::compare($oCloneDate, $this->date); switch ($this->comparison) { case '==': return $val == 0; break; case '!=': return $val != 0; break; case '<=': return $val == -1 || $val == 0; break; case '>=': return $val == 1 || $val == 0; break; case '<': return $val == -1; break; case '>': return $val == 1; break; } return 0; }
/** * The implementation of the OA_Task::run() method that performs * the required task of logging the completion of the MSE process. * * @param PEAR::Date $oEndDate Optional date/time representing the end of the tasks. */ function run($oEndDate = null) { $oServiceLocator =& OA_ServiceLocator::instance(); $oNowDate =& $oServiceLocator->get('now'); if (is_null($oEndDate)) { $oEndDate = new Date(); } // Prepare the duraction to log from the start and end dates $oDuration = new Date_Span(); $oStartDateCopy = new Date(); $oStartDateCopy->copy($oNowDate); $oEndDateCopy = new Date(); $oEndDateCopy->copy($oEndDate); $oDuration->setFromDateDiff($oStartDateCopy, $oEndDateCopy); $message = '- Logging the completion of the maintenance statistics run'; $this->oController->report .= "{$message}.\n"; OA::debug($message, PEAR_LOG_DEBUG); // Determine the type of MSE completion logging required if ($this->oController->updateFinal && $this->oController->updateIntermediate) { // Need to log that both the intermediate and final tables were updated; // however, need to ensure that we log the correct "updated to" times $oUpdateIntermediateToDate = new Date(); $oUpdateIntermediateToDate->copy($this->oController->oUpdateIntermediateToDate); $oUpdateFinalToDate = new Date(); $oUpdateFinalToDate->copy($this->oController->oUpdateFinalToDate); if ($oUpdateIntermediateToDate->equals($oUpdateFinalToDate)) { // The dates are the same, log info with one row $doLog_maintenance_statistics = OA_Dal::factoryDO('log_maintenance_statistics'); $doLog_maintenance_statistics->start_run = $oNowDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->end_run = $oEndDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->duration = $oDuration->toSeconds(); $doLog_maintenance_statistics->adserver_run_type = OX_DAL_MAINTENANCE_STATISTICS_UPDATE_BOTH; $doLog_maintenance_statistics->updated_to = $this->oController->oUpdateIntermediateToDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->insert(); } else { // The dates are not the same, log info with two rows $doLog_maintenance_statistics = OA_Dal::factoryDO('log_maintenance_statistics'); $doLog_maintenance_statistics->start_run = $oNowDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->end_run = $oEndDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->duration = $oDuration->toSeconds(); $doLog_maintenance_statistics->adserver_run_type = OX_DAL_MAINTENANCE_STATISTICS_UPDATE_OI; $doLog_maintenance_statistics->updated_to = $this->oController->oUpdateIntermediateToDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->insert(); $doLog_maintenance_statistics = OA_Dal::factoryDO('log_maintenance_statistics'); $doLog_maintenance_statistics->start_run = $oNowDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->end_run = $oEndDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->duration = $oDuration->toSeconds(); $doLog_maintenance_statistics->adserver_run_type = OX_DAL_MAINTENANCE_STATISTICS_UPDATE_HOUR; $doLog_maintenance_statistics->updated_to = $this->oController->oUpdateFinalToDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->insert(); } } else { if ($this->oController->updateIntermediate) { $doLog_maintenance_statistics = OA_Dal::factoryDO('log_maintenance_statistics'); $doLog_maintenance_statistics->start_run = $oNowDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->end_run = $oEndDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->duration = $oDuration->toSeconds(); $doLog_maintenance_statistics->adserver_run_type = OX_DAL_MAINTENANCE_STATISTICS_UPDATE_OI; $doLog_maintenance_statistics->updated_to = $this->oController->oUpdateIntermediateToDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->insert(); } else { if ($this->oController->updateFinal) { $doLog_maintenance_statistics = OA_Dal::factoryDO('log_maintenance_statistics'); $doLog_maintenance_statistics->start_run = $oNowDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->end_run = $oEndDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->duration = $oDuration->toSeconds(); $doLog_maintenance_statistics->adserver_run_type = OX_DAL_MAINTENANCE_STATISTICS_UPDATE_HOUR; $doLog_maintenance_statistics->updated_to = $this->oController->oUpdateFinalToDate->format('%Y-%m-%d %H:%M:%S'); $doLog_maintenance_statistics->insert(); } else { return false; } } } // Log the report to the "user log" $this->_setMaintenanceStatisticsRunReport($this->oController->report); return true; }
/** * A method to activate/deactivate campaigns, based on the date and/or the inventory * requirements (impressions, clicks and/or conversions). Also sends email reports * for any campaigns that are activated/deactivated, as well as sending email reports * for any campaigns that are likely to expire in the near future. * * @param Date $oDate The current date/time. * @return string Report on the campaigns activated/deactivated. */ function manageCampaigns($oDate) { $aConf = $GLOBALS['_MAX']['CONF']; $oServiceLocator =& OA_ServiceLocator::instance(); $oEmail =& $oServiceLocator->get('OA_Email'); if ($oEmail === false) { $oEmail = new OA_Email(); $oServiceLocator->register('OA_Email', $oEmail); } $report = "\n"; // Select all campaigns in the system, where: // The campaign is ACTIVE and: // - The end date stored for the campaign is not null; or // - The campaign has a lifetime impression, click or conversion // target set. // // That is: // - It is possible for the active campaign to be automatically // stopped, as it has a valid end date. (No limitations are // applied to those campaigns tested, as the ME may not have // run for a while, and if so, even campaigns with an end date // of many, many weeks ago should be tested to ensure they are // [belatedly] halted.) // - It is possible for the active campaign to be automatically // stopped, as it has at leaast one lifetime target that could // have been reached. // // The campaign is INACTIVE and: // - The start date stored for the campaign is not null; and // - The weight is greater than zero; and // - The end date stored for the campaign is either null, or is // greater than "today" less one day. // // That is: // - It is possible for the inactive campaign to be automatically // started, as it has a valid start date. (No limitations are // applied to those campaigns tested, as the ME may not have run // for a while, and if so, even campaigns with an activation date // of many, many weeks ago should be tested to ensure they are // [belatedy] enabled.) // - The campaign is not in a permanently inactive state, as a // result of the weight being less then one, which means that // it cannot be activated. // - The test to start the campaign is unlikely to fail on account // of the end date. (Inactive campaigns with start dates may have // passed the start date, but they may also have passed the end // date - unfortunately, because the dates are not stored in UTC, // it's not possible to know exactly which campaigns have passed // the end date or not, until the values are converted to UTC based // on the Advertiser Account timezone preference - so it's necessary // to get some campaigns that might be passed the end date, and do // the converstion to UTC and test to check.) $prefix = $this->getTablePrefix(); $oYesterdayDate = new Date(); $oYesterdayDate->copy($oDate); $oYesterdayDate->subtractSeconds(SECONDS_PER_DAY); $query = "\n SELECT\n cl.clientid AS advertiser_id,\n cl.account_id AS advertiser_account_id,\n cl.agencyid AS agency_id,\n cl.contact AS contact,\n cl.email AS email,\n cl.reportdeactivate AS send_activate_deactivate_email,\n ca.campaignid AS campaign_id,\n ca.campaignname AS campaign_name,\n ca.views AS targetimpressions,\n ca.clicks AS targetclicks,\n ca.conversions AS targetconversions,\n ca.status AS status,\n ca.activate AS start,\n ca.expire AS end\n FROM\n {$prefix}campaigns AS ca,\n {$prefix}clients AS cl\n WHERE\n ca.clientid = cl.clientid\n AND\n ca.status = " . $this->oDbh->quote(OA_ENTITY_STATUS_RUNNING, 'integer') . "\n AND\n (\n ca.expire " . OA_Dal::notEqualNoDateString() . "\n OR\n (\n ca.views > 0\n OR\n ca.clicks > 0\n OR\n ca.conversions > 0\n )\n )\n UNION ALL\n SELECT\n cl.clientid AS advertiser_id,\n cl.account_id AS advertiser_account_id,\n cl.agencyid AS agency_id,\n cl.contact AS contact,\n cl.email AS email,\n cl.reportdeactivate AS send_activate_deactivate_email,\n ca.campaignid AS campaign_id,\n ca.campaignname AS campaign_name,\n ca.views AS targetimpressions,\n ca.clicks AS targetclicks,\n ca.conversions AS targetconversions,\n ca.status AS status,\n ca.activate AS start,\n ca.expire AS end\n FROM\n {$prefix}campaigns AS ca,\n {$prefix}clients AS cl\n WHERE\n ca.clientid = cl.clientid\n AND\n ca.status != " . $this->oDbh->quote(OA_ENTITY_STATUS_RUNNING, 'integer') . "\n AND\n ca.activate " . OA_Dal::notEqualNoDateString() . "\n AND\n (\n ca.weight > 0\n OR\n ca.priority > 0\n )\n AND\n (\n ca.expire >= " . $this->oDbh->quote($oYesterdayDate->format('%Y-%m-%d'), 'timestamp') . "\n OR\n ca.expire " . OA_Dal::equalNoDateString() . "\n )\n ORDER BY\n advertiser_id"; $rsResult = $this->oDbh->query($query); if (PEAR::isError($rsResult)) { return MAX::raiseError($rsResult, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } OA::debug('- Found ' . $rsResult->numRows() . ' campaigns to test for activation/deactivation', PEAR_LOG_DEBUG); while ($aCampaign = $rsResult->fetchRow()) { if ($aCampaign['status'] == OA_ENTITY_STATUS_RUNNING) { // The campaign is currently running, look at the campaign $disableReason = 0; $canExpireSoon = false; if ($aCampaign['targetimpressions'] > 0 || $aCampaign['targetclicks'] > 0 || $aCampaign['targetconversions'] > 0) { // The campaign has an impression, click and/or conversion target, // so get the sum total statistics for the campaign $query = "\n SELECT\n SUM(dia.impressions) AS impressions,\n SUM(dia.clicks) AS clicks,\n SUM(dia.conversions) AS conversions\n FROM\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['data_intermediate_ad'], true) . " AS dia,\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['banners'], true) . " AS b\n WHERE\n dia.ad_id = b.bannerid\n AND b.campaignid = {$aCampaign['campaign_id']}"; $rsResultInner = $this->oDbh->query($query); $valuesRow = $rsResultInner->fetchRow(); if (!is_null($valuesRow['impressions']) || !is_null($valuesRow['clicks']) || !is_null($valuesRow['conversions'])) { // There were impressions, clicks and/or conversions for this // campaign, so find out if campaign targets have been passed if (is_null($valuesRow['impressions'])) { // No impressions $valuesRow['impressions'] = 0; } if (is_null($valuesRow['clicks'])) { // No clicks $valuesRow['clicks'] = 0; } if (is_null($valuesRow['conversions'])) { // No conversions $valuesRow['conversions'] = 0; } if ($aCampaign['targetimpressions'] > 0) { if ($aCampaign['targetimpressions'] <= $valuesRow['impressions']) { // The campaign has an impressions target, and this has been // passed, so update and disable the campaign $disableReason |= OX_CAMPAIGN_DISABLED_IMPRESSIONS; } } if ($aCampaign['targetclicks'] > 0) { if ($aCampaign['targetclicks'] <= $valuesRow['clicks']) { // The campaign has a click target, and this has been // passed, so update and disable the campaign $disableReason |= OX_CAMPAIGN_DISABLED_CLICKS; } } if ($aCampaign['targetconversions'] > 0) { if ($aCampaign['targetconversions'] <= $valuesRow['conversions']) { // The campaign has a target limitation, and this has been // passed, so update and disable the campaign $disableReason |= OX_CAMPAIGN_DISABLED_CONVERSIONS; } } if ($disableReason) { // One of the campaign targets was exceeded, so disable $message = '- Exceeded a campaign quota: Deactivating campaign ID ' . "{$aCampaign['campaign_id']}: {$aCampaign['campaign_name']}"; OA::debug($message, PEAR_LOG_INFO); $report .= $message . "\n"; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->campaignid = $aCampaign['campaign_id']; $doCampaigns->find(); $doCampaigns->fetch(); $doCampaigns->status = OA_ENTITY_STATUS_EXPIRED; $result = $doCampaigns->update(); if ($result == false) { return MAX::raiseError($rows, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } phpAds_userlogSetUser(phpAds_userMaintenance); phpAds_userlogAdd(phpAds_actionDeactiveCampaign, $aCampaign['campaign_id']); } else { // The campaign didn't have a diable reason, // it *might* possibly be diabled "soon"... $canExpireSoon = true; } } } // Does the campaign need to be disabled due to the date? if ($aCampaign['end'] != OA_Dal::noDateValue()) { // The campaign has a valid end date, stored in the timezone of the advertiser; // create an end date in the advertiser's timezone, set the time, and then // convert to UTC so that it can be compared with the MSE run time, which is // in UTC $aAdvertiserPrefs = OA_Preferences::loadAccountPreferences($aCampaign['advertiser_account_id'], true); $oTimezone = new Date_Timezone($aAdvertiserPrefs['timezone']); $oEndDate = new Date(); $oEndDate->convertTZ($oTimezone); $oEndDate->setDate($aCampaign['end'] . ' 23:59:59'); // Campaigns end at the end of the day $oEndDate->toUTC(); if ($oDate->after($oEndDate)) { // The end date has been passed; disable the campaign $disableReason |= OX_CAMPAIGN_DISABLED_DATE; $message = "- Passed campaign end time of '{$aCampaign['end']} 23:59:59 {$aAdvertiserPrefs['timezone']} (" . $oEndDate->format('%Y-%m-%d %H:%M:%S') . ' ' . $oEndDate->tz->getShortName() . ")': Deactivating campaign ID {$aCampaign['campaign_id']}: {$aCampaign['campaign_name']}"; OA::debug($message, PEAR_LOG_INFO); $report .= $message . "\n"; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->campaignid = $aCampaign['campaign_id']; $doCampaigns->find(); $doCampaigns->fetch(); $doCampaigns->status = OA_ENTITY_STATUS_EXPIRED; $result = $doCampaigns->update(); if ($result == false) { return MAX::raiseError($rows, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } phpAds_userlogSetUser(phpAds_userMaintenance); phpAds_userlogAdd(phpAds_actionDeactiveCampaign, $aCampaign['campaign_id']); } else { // The campaign wasn't disabled based on the end // date, to it *might* possibly be disabled "soon"... $canExpireSoon = true; } } if ($disableReason) { // The campaign was disabled, so send the appropriate // message to the campaign's contact $query = "\n SELECT\n bannerid AS advertisement_id,\n description AS description,\n alt AS alt,\n url AS url\n FROM\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['banners'], true) . "\n WHERE\n campaignid = {$aCampaign['campaign_id']}"; OA::debug("- Getting the advertisements for campaign ID {$aCampaign['campaign_id']}", PEAR_LOG_DEBUG); $rsResultAdvertisement = $this->oDbh->query($query); if (PEAR::isError($rsResultAdvertisement)) { return MAX::raiseError($rsResultAdvertisement, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } while ($advertisementRow = $rsResultAdvertisement->fetchRow()) { $advertisements[$advertisementRow['advertisement_id']] = array($advertisementRow['description'], $advertisementRow['alt'], $advertisementRow['url']); } if ($aCampaign['send_activate_deactivate_email'] == 't') { $oEmail->sendCampaignActivatedDeactivatedEmail($aCampaign['campaign_id'], $disableReason); } } else { if ($canExpireSoon) { // The campaign has NOT been deactivated - test to see if it will // be deactivated "soon", and send email(s) warning of this as required $oEmail->sendCampaignImpendingExpiryEmail($oDate, $aCampaign['campaign_id']); } } } else { // The campaign is not active - does it need to be enabled, // based on the campaign starting date? if ($aCampaign['start'] != OA_Dal::noDateValue()) { // The campaign has a valid start date, stored in the timezone of the advertiser; // create an end date in the advertiser's timezone, set the time, and then // convert to UTC so that it can be compared with the MSE run time, which is // in UTC $aAdvertiserPrefs = OA_Preferences::loadAccountPreferences($aCampaign['advertiser_account_id'], true); $oTimezone = new Date_Timezone($aAdvertiserPrefs['timezone']); $oStartDate = new Date(); $oStartDate->convertTZ($oTimezone); $oStartDate->setDate($aCampaign['start'] . ' 00:00:00'); // Campaigns start at the start of the day $oStartDate->toUTC(); if ($aCampaign['end'] != OA_Dal::noDateValue()) { // The campaign has a valid end date, stored in the timezone of the advertiser; // create an end date in the advertiser's timezone, set the time, and then // convert to UTC so that it can be compared with the MSE run time, which is // in UTC $oEndDate = new Date(); $oEndDate->convertTZ($oTimezone); $oEndDate->setDate($aCampaign['end'] . ' 23:59:59'); // Campaign end at the end of the day $oEndDate->toUTC(); } else { $oEndDate = null; } if ($oDate->after($oStartDate)) { // The start date has been passed; find out if there are any impression, click // or conversion targets for the campaign (i.e. if the target values are > 0) $remainingImpressions = 0; $remainingClicks = 0; $remainingConversions = 0; if ($aCampaign['targetimpressions'] > 0 || $aCampaign['targetclicks'] > 0 || $aCampaign['targetconversions'] > 0) { // The campaign has an impression, click and/or conversion target, // so get the sum total statistics for the campaign so far $query = "\n SELECT\n SUM(dia.impressions) AS impressions,\n SUM(dia.clicks) AS clicks,\n SUM(dia.conversions) AS conversions\n FROM\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['data_intermediate_ad'], true) . " AS dia,\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['banners'], true) . " AS b\n WHERE\n dia.ad_id = b.bannerid\n AND b.campaignid = {$aCampaign['campaign_id']}"; $rsResultInner = $this->oDbh->query($query); $valuesRow = $rsResultInner->fetchRow(); // Set the remaining impressions, clicks and conversions for the campaign $remainingImpressions = $aCampaign['targetimpressions'] - $valuesRow['impressions']; $remainingClicks = $aCampaign['targetclicks'] - $valuesRow['clicks']; $remainingConversions = $aCampaign['targetconversions'] - $valuesRow['conversions']; } // In order for the campaign to be activated, need to test: // 1) That there is no impression target (<= 0), or, if there is an impression target (> 0), // then there must be remaining impressions to deliver (> 0); and // 2) That there is no click target (<= 0), or, if there is a click target (> 0), // then there must be remaining clicks to deliver (> 0); and // 3) That there is no conversion target (<= 0), or, if there is a conversion target (> 0), // then there must be remaining conversions to deliver (> 0); and // 4) Either there is no end date, or the end date has not been passed if (($aCampaign['targetimpressions'] <= 0 || $aCampaign['targetimpressions'] > 0 && $remainingImpressions > 0) && ($aCampaign['targetclicks'] <= 0 || $aCampaign['targetclicks'] > 0 && $remainingClicks > 0) && ($aCampaign['targetconversions'] <= 0 || $aCampaign['targetconversions'] > 0 && $remainingConversions > 0) && (is_null($oEndDate) || $oEndDate->format('%Y-%m-%d') != OA_Dal::noDateValue() && Date::compare($oDate, $oEndDate) < 0)) { $message = "- Passed campaign start time of '{$aCampaign['start']} 00:00:00 {$aAdvertiserPrefs['timezone']} (" . $oStartDate->format('%Y-%m-%d %H:%M:%S') . ' ' . $oStartDate->tz->getShortName() . ")': Activating campaign ID {$aCampaign['campaign_id']}: {$aCampaign['campaign_name']}"; OA::debug($message, PEAR_LOG_INFO); $report .= $message . "\n"; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->campaignid = $aCampaign['campaign_id']; $doCampaigns->find(); $doCampaigns->fetch(); $doCampaigns->status = OA_ENTITY_STATUS_RUNNING; $result = $doCampaigns->update(); if ($result == false) { return MAX::raiseError($rows, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } phpAds_userlogSetUser(phpAds_userMaintenance); phpAds_userlogAdd(phpAds_actionActiveCampaign, $aCampaign['campaign_id']); // Get the advertisements associated with the campaign $query = "\n SELECT\n bannerid AS advertisement_id,\n description AS description,\n alt AS alt,\n url AS url\n FROM\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['banners'], true) . "\n WHERE\n campaignid = {$aCampaign['campaign_id']}"; OA::debug("- Getting the advertisements for campaign ID {$aCampaign['campaign_id']}", PEAR_LOG_DEBUG); $rsResultAdvertisement = $this->oDbh->query($query); if (PEAR::isError($rsResultAdvertisement)) { return MAX::raiseError($rsResultAdvertisement, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } while ($advertisementRow = $rsResultAdvertisement->fetchRow()) { $advertisements[$advertisementRow['advertisement_id']] = array($advertisementRow['description'], $advertisementRow['alt'], $advertisementRow['url']); } if ($aCampaign['send_activate_deactivate_email'] == 't') { $oEmail->sendCampaignActivatedDeactivatedEmail($aCampaign['campaign_id']); } } } } } } }
function get_weekly_volume_graph($userID, $connection) { $beg_date = new Date(); $end_date = new Date(); $wk = array(0, 0, 0, 0, 0, 0, 0); $wk_actual = array(0, 0, 0, 0, 0, 0, 0); $label = array(0, 0, 0, 0, 0, 0, 0); $filename = array("filename" => "/var/www/vanhlebarsoftware/fitlog/graphs/wklygraph.jpg"); // Get current weeks and prior three weeks volume numbers and the next three weeks. $day_of_wk = $beg_date->getDayOfWeek(); $beg_date->addDays(-($day_of_wk - 1) + 21); $end_date->copy($beg_date); $end_date->addDays(6); for ($i = 0; $i < 7; $i++) { // Get the planned volume for this particular week. $query = "SELECT SUM(seconds) AS seconds FROM flmain WHERE workout_date>='" . $beg_date->format("%Y-%m-%d") . "' AND workout_date<='" . $end_date->format("%Y-%m-%d") . "' AND user_id=" . $userID . " AND plan_type='p'"; $queryStr = "SELECT SUM(seconds) AS seconds FROM flstrength WHERE workout_date>='" . $beg_date->format("%Y-%m-%d") . "' AND workout_date<='" . $end_date->format("%Y-%m-%d") . "' AND user_id=" . $userID . " AND plan_type='p'"; $result = @mysql_query($query, $connection); $resultStr = @mysql_query($query, $connection); if ($result || $resultStr) { $tmp = 0; if ($result) { $row = mysql_fetch_array($result); $tmp = convert_seconds_minutes($row["seconds"]); } if ($resultStr) { $rowStr = mysql_fetch_array($resultStr); $tmp += convert_seconds_minutes($rowStr["seconds"]); } $wk[$i] = $tmp; } else { $wk[$i] = 0; } // Get the actual volume for this particular week. $query = "SELECT SUM(seconds) AS seconds FROM flmain WHERE workout_date>='" . $beg_date->format("%Y-%m-%d") . "' AND workout_date<='" . $end_date->format("%Y-%m-%d") . "' AND user_id=" . $userID . " AND plan_type='a'"; $queryStr = "SELECT SUM(seconds) AS seconds FROM flstrength WHERE workout_date>='" . $beg_date->format("%Y-%m-%d") . "' AND workout_date<='" . $end_date->format("%Y-%m-%d") . "' AND user_id=" . $userID . " AND plan_type='a'"; $result = @mysql_query($query, $connection); $resultStr = @mysql_query($queryStr, $connection); if ($result || $resultStr) { $tmp = 0; if ($result) { $row = mysql_fetch_array($result); $tmp = convert_seconds_minutes($row["seconds"]); } if ($resultStr) { $rowStr = mysql_fetch_array($resultStr); $tmp += convert_seconds_minutes($rowStr["seconds"]); } $wk_actual[$i] = $tmp; } else { $wk_actual[$i] = 0; } // Create the labels. $label[$i] = $end_date->format("%m/%d"); // Move the dates back by one week. $beg_date->addDays(-7); $end_date->addDays(-7); } for ($i = 0; $i < 7; $i++) { } //Setup the graph. $Graph =& Image_Graph::factory('graph', array(300, 210, TRUE)); $Graph->add(Image_Graph::factory('title', array('Weekly Volume - Actual vs. Planned'), 12)); $Plotarea =& $Graph->addNew('plotarea'); $Dataset =& Image_Graph::factory('dataset'); $Dataset1 =& Image_Graph::factory('dataset'); // Add the actual volume to the graph. $Dataset1->addPoint($label[6], $wk_actual[6]); $Dataset1->addPoint($label[5], $wk_actual[5]); $Dataset1->addPoint($label[4], $wk_actual[4]); $Dataset1->addPoint($label[3], $wk_actual[3]); $Dataset1->addPoint($label[2], $wk_actual[2]); $Dataset1->addPoint($label[1], $wk_actual[1]); $Dataset1->addPoint($label[0], $wk_actual[0]); // Add the planned volume to the graph. $Dataset->addPoint($label[6], $wk[6]); $Dataset->addPoint($label[5], $wk[5]); $Dataset->addPoint($label[4], $wk[4]); $Dataset->addPoint($label[3], $wk[3]); $Dataset->addPoint($label[2], $wk[2]); $Dataset->addPoint($label[1], $wk[1]); $Dataset->addPoint($label[0], $wk[0]); // Plot the actual data to the graph. $Plot =& $Plotarea->addNew('line', &$Dataset); $Plot1 =& $Plotarea->addNew('bar', &$Dataset1); $Plot1->setFillColor('green@.8'); // Set the axis titles. $YAxis =& $Plotarea->getAxis(IMAGE_GRAPH_AXIS_Y); $YAxis->setTitle('Minutes', 'vertical'); $XAxis =& $Plotarea->getAxis(IMAGE_GRAPH_AXIS_X); $XAxis->setTitle("Week", array('angle' => 0)); //Output the finished graph to the graphs directory. $result = $Graph->done($filename); if ($result) { var_dump("error creating graph!"); } }
/** * A method to test the sending of emails from the * manageCampaigns() method - tests the sending of * the "campaign activated" emails. */ function testManageCampaignsEmailsPlacementActivated() { // Set now as 1 week before $oDateNow = new Date(); $oDateNow->subtractSpan(new Date_Span('7-0-0-0')); $oServiceLocator =& OA_ServiceLocator::instance(); $oServiceLocator->register('now', $oDateNow); // Create the required accounts & set the various ID values $aValues = $this->_createAccounts(); $managerAgencyId = $aValues['managerAgency']; // Prepare a single placement that is inactive, and has an old // activation date (so that it will need to be activated) $aData = array('agencyid' => $managerAgencyId, 'contact' => 'Test Placement Activated Contact', 'email' => '*****@*****.**', 'reportdeactivate' => 't'); $advertiserId = $this->_insertAdvertiser($aData); $oDate = new Date(); $oDateStart = new Date(); $oDateStart->copy($oDate); $oDateStart->subtractSeconds(SECONDS_PER_HOUR + 1); $aData = array('clientid' => $advertiserId, 'status' => OA_ENTITY_STATUS_AWAITING, 'activate_time' => $oDateStart->format('%Y-%m-%d 00:00:00')); $campaignId = $this->_insertPlacement($aData); // Reset now $oServiceLocator->remove('now'); $aData = array('campaignid' => $campaignId); $adId = $this->_insertAd($aData); // Create an instance of the mocked OA_Email class, and set // expectations on how the class' methods should be called // based on the above Mock::generate('OA_Email'); $oEmailMock = new MockOA_Email($this); $oEmailMock->expectOnce('sendCampaignActivatedDeactivatedEmail', array("{$campaignId}")); // Register the mocked OA_Email class in the service locator $oServiceLocator =& OA_ServiceLocator::instance(); $oServiceLocator->register('OA_Email', $oEmailMock); // Run the manageCampaigns() method and ensure that the correct // calls to OA_Email were made $oDate = new Date(); $oFactory = new OX_Dal_Maintenance_Statistics_Factory(); $oDalMaintenanceStatistics = $oFactory->factory(); $report = $oDalMaintenanceStatistics->manageCampaigns($oDate); $oEmailMock->tally(); // Clean up DataGenerator::cleanUp(); }
/** * Method to test the updatePriorities method. * * Test 1: Test with no Date registered in the service locator, ensure false returned. * Test 2: Test with no data in the database, ensure data is correctly stored. * Test 3: Test with previous test data in the database, ensure data is correctly stored. * Test 4: Test with an obscene number of items, and ensure that the packet size is * not exceeded (no asserts, test suite will simply fail if unable to work). */ function testUpdatePriorities() { /** * @TODO Locate where clean up doesn't happen before this test, and fix! */ TestEnv::restoreEnv(); $conf = $GLOBALS['_MAX']['CONF']; $oDbh =& OA_DB::singleton(); $oMaxDalMaintenance = new OA_Dal_Maintenance_Priority(); // Insert the data into the ad_zone_assoc table, as an ad is linked to a zone $this->_generateTestData(); // Test 1 $oServiceLocator =& OA_ServiceLocator::instance(); $oServiceLocator->remove('now'); $aData = array(array('ads' => array(array('ad_id' => $this->aIds['ad'], 'zone_id' => $this->aIds['zone'], 'required_impressions' => '1000', 'requested_impressions' => '1000', 'priority' => '0.45', 'priority_factor' => null, 'priority_factor_limited' => false, 'past_zone_traffic_fraction' => null)))); $result = $oMaxDalMaintenance->updatePriorities($aData); $this->assertFalse($result); // Test 2 $oDate = new Date(); $oServiceLocator->register('now', $oDate); $result = $oMaxDalMaintenance->updatePriorities($aData); $this->assertTrue($result); $query = "\n SELECT\n ad_id,\n zone_id,\n priority\n FROM\n " . $oDbh->quoteIdentifier($conf['table']['prefix'] . $conf['table']['ad_zone_assoc'], true) . "\n WHERE\n ad_id = {$this->aIds['ad']} AND zone_id = {$this->aIds['zone']}"; $rc = $oDbh->query($query); $aRow = $rc->fetchRow(); $this->assertEqual($aRow['ad_id'], $this->aIds['ad']); $this->assertEqual($aRow['zone_id'], $this->aIds['zone']); $this->assertEqual($aRow['priority'], 0.45); $query = "\n SELECT\n operation_interval,\n operation_interval_id,\n interval_start,\n interval_end,\n ad_id,\n zone_id,\n required_impressions,\n requested_impressions,\n priority,\n priority_factor,\n priority_factor_limited,\n past_zone_traffic_fraction,\n created,\n created_by,\n expired,\n expired_by\n FROM\n " . $oDbh->quoteIdentifier($conf['table']['prefix'] . $conf['table']['data_summary_ad_zone_assoc'], true) . "\n WHERE\n ad_id = {$this->aIds['ad']}"; $rc = $oDbh->query($query); $aRow = $rc->fetchRow(); $currentOperationIntervalID = OX_OperationInterval::convertDateToOperationIntervalID($oDate); $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oDate); $this->assertEqual($aRow['operation_interval'], $conf['maintenance']['operationInterval']); $this->assertEqual($aRow['operation_interval_id'], $currentOperationIntervalID); $this->assertEqual($aRow['interval_start'], $aDates['start']->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['interval_end'], $aDates['end']->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['ad_id'], $this->aIds['ad']); $this->assertEqual($aRow['zone_id'], $this->aIds['zone']); $this->assertEqual($aRow['required_impressions'], 1000); $this->assertEqual($aRow['requested_impressions'], 1000); $this->assertEqual($aRow['priority'], 0.45); $this->assertNull($aRow['priority_factor']); $this->assertFalse($aRow['priority_factor_limited']); $this->assertNull($aRow['past_zone_traffic_fraction']); $this->assertEqual($aRow['created'], $oDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['created_by'], 0); $this->assertNull($aRow['expired']); $this->assertNull($aRow['expired_by']); // Test 3 $aData = array(array('ads' => array(array('ad_id' => $this->aIds['ad'], 'zone_id' => $this->aIds['zone'], 'required_impressions' => 2000, 'requested_impressions' => 2000, 'priority' => 0.9, 'priority_factor' => 0.1, 'priority_factor_limited' => false, 'past_zone_traffic_fraction' => 0.99), array('ad_id' => $this->aIds['ad'] + 1, 'zone_id' => $this->aIds['ad'] + 1, 'required_impressions' => 500, 'requested_impressions' => 500, 'priority' => 0.1, 'priority_factor' => 0.2, 'priority_factor_limited' => true, 'past_zone_traffic_fraction' => 0.45)))); $oOldDate = new Date(); $oOldDate->copy($oDate); $oDate = new Date(); $oServiceLocator->register('now', $oDate); $result = $oMaxDalMaintenance->updatePriorities($aData); $this->assertTrue($result); $query = "\n SELECT\n ad_id,\n zone_id,\n priority\n FROM\n " . $oDbh->quoteIdentifier($conf['table']['prefix'] . $conf['table']['ad_zone_assoc'], true) . "\n WHERE\n ad_id = {$this->aIds['ad']} AND zone_id = {$this->aIds['zone']}"; $rc = $oDbh->query($query); $aRow = $rc->fetchRow(); $this->assertEqual($aRow['ad_id'], $this->aIds['ad']); $this->assertEqual($aRow['zone_id'], $this->aIds['zone']); $this->assertEqual($aRow['priority'], 0.9); $query = "\n SELECT\n operation_interval,\n operation_interval_id,\n interval_start,\n interval_end,\n ad_id,\n zone_id,\n required_impressions,\n requested_impressions,\n priority,\n priority_factor,\n priority_factor_limited,\n past_zone_traffic_fraction,\n created,\n created_by,\n expired,\n expired_by\n FROM\n " . $oDbh->quoteIdentifier($conf['table']['prefix'] . $conf['table']['data_summary_ad_zone_assoc'], true) . "\n WHERE\n ad_id = {$this->aIds['ad']}\n AND expired IS NOT NULL"; $rc = $oDbh->query($query); $aRow = $rc->fetchRow(); $currentOperationIntervalID = OX_OperationInterval::convertDateToOperationIntervalID($oOldDate); $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oOldDate); $this->assertEqual($aRow['operation_interval'], $conf['maintenance']['operationInterval']); $this->assertEqual($aRow['operation_interval_id'], $currentOperationIntervalID); $this->assertEqual($aRow['interval_start'], $aDates['start']->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['interval_end'], $aDates['end']->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['ad_id'], $this->aIds['ad']); $this->assertEqual($aRow['zone_id'], $this->aIds['ad']); $this->assertEqual($aRow['required_impressions'], 1000); $this->assertEqual($aRow['requested_impressions'], 1000); $this->assertEqual($aRow['priority'], 0.45); $this->assertNull($aRow['priority_factor']); $this->assertFalse($aRow['priority_factor_limited']); $this->assertNull($aRow['past_zone_traffic_fraction']); $this->assertEqual($aRow['created'], $oOldDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['created_by'], 0); $this->assertEqual($aRow['expired'], $oDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['expired_by'], 0); $query = "\n SELECT\n operation_interval,\n operation_interval_id,\n interval_start,\n interval_end,\n ad_id,\n zone_id,\n required_impressions,\n requested_impressions,\n priority,\n priority_factor,\n priority_factor_limited,\n past_zone_traffic_fraction,\n created,\n created_by,\n expired,\n expired_by\n FROM\n " . $oDbh->quoteIdentifier($conf['table']['prefix'] . $conf['table']['data_summary_ad_zone_assoc'], true) . "\n WHERE\n ad_id = {$this->aIds['ad']}\n AND expired IS NULL"; $rc = $oDbh->query($query); $aRow = $rc->fetchRow(); $currentOperationIntervalID = OX_OperationInterval::convertDateToOperationIntervalID($oDate); $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oDate); $this->assertEqual($aRow['operation_interval'], $conf['maintenance']['operationInterval']); $this->assertEqual($aRow['operation_interval_id'], $currentOperationIntervalID); $this->assertEqual($aRow['interval_start'], $aDates['start']->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['interval_end'], $aDates['end']->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['ad_id'], $this->aIds['ad']); $this->assertEqual($aRow['zone_id'], $this->aIds['ad']); $this->assertEqual($aRow['required_impressions'], 2000); $this->assertEqual($aRow['requested_impressions'], 2000); $this->assertEqual($aRow['priority'], 0.9); $this->assertEqual($aRow['priority_factor'], 0.1); $this->assertFalse($aRow['priority_factor_limited']); $this->assertEqual($aRow['past_zone_traffic_fraction'], 0.99); $this->assertEqual($aRow['created'], $oDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['created_by'], 0); $this->assertNull($aRow['expired']); $this->assertNull($aRow['expired_by']); $query = "\n SELECT\n operation_interval,\n operation_interval_id,\n interval_start,\n interval_end,\n ad_id,\n zone_id,\n required_impressions,\n requested_impressions,\n priority,\n priority_factor,\n priority_factor_limited,\n past_zone_traffic_fraction,\n created,\n created_by,\n expired,\n expired_by\n FROM\n " . $oDbh->quoteIdentifier($conf['table']['prefix'] . $conf['table']['data_summary_ad_zone_assoc'], true) . "\n WHERE\n ad_id = " . ($this->aIds['ad'] + 1); $rc = $oDbh->query($query); $aRow = $rc->fetchRow(); $currentOperationIntervalID = OX_OperationInterval::convertDateToOperationIntervalID($oDate); $aDates = OX_OperationInterval::convertDateToOperationIntervalStartAndEndDates($oDate); $this->assertEqual($aRow['operation_interval'], $conf['maintenance']['operationInterval']); $this->assertEqual($aRow['operation_interval_id'], $currentOperationIntervalID); $this->assertEqual($aRow['interval_start'], $aDates['start']->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['interval_end'], $aDates['end']->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['ad_id'], $this->aIds['ad'] + 1); $this->assertEqual($aRow['zone_id'], $this->aIds['ad'] + 1); $this->assertEqual($aRow['required_impressions'], 500); $this->assertEqual($aRow['requested_impressions'], 500); $this->assertEqual($aRow['priority'], 0.1); $this->assertEqual($aRow['priority_factor'], 0.2); $this->assertTrue($aRow['priority_factor_limited']); $this->assertEqual($aRow['past_zone_traffic_fraction'], 0.45); $this->assertEqual($aRow['created'], $oDate->format('%Y-%m-%d %H:%M:%S')); $this->assertEqual($aRow['created_by'], 0); $this->assertNull($aRow['expired']); $this->assertNull($aRow['expired_by']); // Test 4 $aData = array(); for ($i = 1; $i < 5000; $i++) { $aData[$i] = array('ads' => array(array('ad_id' => $i, 'zone_id' => $i, 'required_impressions' => 2000, 'requested_impressions' => 2000, 'priority' => 0.9, 'priority_factor' => 0.1, 'priority_factor_limited' => false, 'past_zone_traffic_fraction' => 0.99))); } $oOldDate = new Date(); $oOldDate->copy($oDate); $oDate = new Date(); $oServiceLocator->register('now', $oDate); $result = $oMaxDalMaintenance->updatePriorities($aData); TestEnv::restoreEnv('dropTmpTables'); }
/** * A method to test the getDaysLeftString() method. */ function testGetDaysLeftString() { /* Possible cases for testing: Case 1 -> Campaign without expiration date and without a estimated expiration date yet Case 2 -> Campaign without expiration date and with a estimated expiration date Case 3 -> Campaign with expiration date and without a estimated expiration date Case 4 -> Campaign with expiration date reached Case 5 -> Campaign with expiration date and with estimated expiration date minor than the expiration date Case 6 -> Campaign with expiration date and with estimated expiration date equals to the expiration date Case 7 -> Campaign with expiration date and with estimated expiration date higher than the expiration date */ $GLOBALS['strExpirationDate'] = "Expiration date"; $GLOBALS['strNoExpiration'] = "No expiration date set"; $GLOBALS['strEstimated'] = "Estimated expiration date"; $GLOBALS['strNoExpirationEstimation'] = "No expiration estimated yet"; $GLOBALS['strCampaignStop'] = "Campaign stop"; $GLOBALS['strDaysAgo'] = "days ago"; $GLOBALS['strDaysLeft'] = "Days left"; $GLOBALS['date_format'] = '%d.%m.%Y'; // Case 1 // Test an unlimited campaign without expiration date and without a // estimated expiration date yet $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->views = 0; $doCampaigns->clicks = 0; $doCampaigns->conversions = 0; $aData = array('reportlastdate' => array('2007-04-03 18:39:45')); $dg = new DataGenerator(); $dg->setData('clients', $aData); $aCampaignIds = $dg->generate($doCampaigns, 1, true); $campaignId = $aCampaignIds[0]; $expected = array('estimatedExpiration' => $GLOBALS['strEstimated'] . ": " . $GLOBALS['strNoExpirationEstimation'], 'campaignExpiration' => $GLOBALS['strNoExpiration']); $actual = $this->oDalCampaigns->getDaysLeftString($campaignId); $this->assertEqual($actual, $expected); // Case 2.1 // Test a campaign (an impression limited campaign) without // expiration date and with a estimated expiration date $totalImpressions = 1000; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->views = $totalImpressions; $doCampaigns->clicks = 0; $doCampaigns->conversions = 0; $aData = array('reportlastdate' => array('2007-04-03 18:39:45')); $dg = new DataGenerator(); $dg->setData('clients', $aData); $aCampaignIds = $dg->generate($doCampaigns, 1, true); $campaignId = $aCampaignIds[0]; // Link a banner to this campaign $doBanners = OA_Dal::factoryDO('banners'); $doBanners->campaignid = $campaignId; $doBanners->acls_updated = '2007-04-03 18:39:45'; $bannerId = DataGenerator::generateOne($doBanners); // Insert impression delivery data occurring today $oDate = new Date(); $impressions = 50; $clicks = 5; $conversions = 1; $doDSAH = OA_Dal::factoryDO('data_intermediate_ad'); $doDSAH->day = $oDate->format('%Y-%m-%d'); $doDSAH->hour = 10; $doDSAH->ad_id = $bannerId; $doDSAH->impressions = $impressions; $doDSAH->clicks = $clicks; $doDSAH->conversions = $conversions; $dsahId = DataGenerator::generateOne($doDSAH); // Delivered 50 impressions in 1 day. So, expect to take 19 days // to deliver remaining 950 $daysLeft = 19; $oExpirationDate = new Date(); $oExpirationDate->copy($oDate); $oExpirationDate->addSeconds($daysLeft * SECONDS_PER_DAY); $expected = array('estimatedExpiration' => $GLOBALS['strEstimated'] . ": " . $oExpirationDate->format('%d.%m.%Y') . " (" . $GLOBALS['strDaysLeft'] . ": " . $daysLeft . ")", 'campaignExpiration' => $GLOBALS['strNoExpiration']); $actual = $this->oDalCampaigns->getDaysLeftString($campaignId); $this->assertEqual($actual, $expected); // Case 2.2 // Test a campaign (click limited campaign) without // expiration date and with a estimated expiration date $totalClicks = 500; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->views = 0; $doCampaigns->clicks = $totalClicks; $doCampaigns->conversions = 0; $aData = array('reportlastdate' => array('2007-04-03 18:39:45')); $dg = new DataGenerator(); $dg->setData('clients', $aData); $aCampaignIds = $dg->generate($doCampaigns, 1, true); $campaignId = $aCampaignIds[0]; // Link a banner to this campaign $doBanners = OA_Dal::factoryDO('banners'); $doBanners->campaignid = $campaignId; $doBanners->acls_updated = '2007-04-03 18:39:45'; $bannerId = DataGenerator::generateOne($doBanners); // Insert click delivery data occurring today $oDate = new Date(); $impressions = 50; $clicks = 5; $conversions = 1; $doDSAH = OA_Dal::factoryDO('data_intermediate_ad'); $doDSAH->day = $oDate->format('%Y-%m-%d'); $doDSAH->hour = 10; $doDSAH->ad_id = $bannerId; $doDSAH->impressions = $impressions; $doDSAH->clicks = $clicks; $doDSAH->conversions = $conversions; $dsahId = DataGenerator::generateOne($doDSAH); // Delivered 5 clicks in 1 day. So, expect to take 99 days to deliver // remaining 495 $daysLeft = 99; $oExpirationDate = new Date(); $oExpirationDate->copy($oDate); $oExpirationDate->addSeconds($daysLeft * SECONDS_PER_DAY); $expected = array('estimatedExpiration' => $GLOBALS['strEstimated'] . ": " . $oExpirationDate->format('%d.%m.%Y') . " (" . $GLOBALS['strDaysLeft'] . ": " . $daysLeft . ")", 'campaignExpiration' => $GLOBALS['strNoExpiration']); $actual = $this->oDalCampaigns->getDaysLeftString($campaignId); $this->assertEqual($actual, $expected); // Case 2.3 // Test a campaign (conversion limited campaign) // without expiration date and with a estimated expiration date $totalConversions = 10; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->views = 0; $doCampaigns->clicks = 0; $doCampaigns->conversions = $totalConversions; $aData = array('reportlastdate' => array('2007-04-03 18:39:45')); $dg = new DataGenerator(); $dg->setData('clients', $aData); $aCampaignIds = $dg->generate($doCampaigns, 1, true); $campaignId = $aCampaignIds[0]; // Link a banner to this campaign $doBanners = OA_Dal::factoryDO('banners'); $doBanners->campaignid = $campaignId; $doBanners->acls_updated = '2007-04-03 18:39:45'; $bannerId = DataGenerator::generateOne($doBanners); // Insert conversion delivery data occurring today $oDate = new Date(); $impressions = 50; $clicks = 5; $conversions = 1; $doDSAH = OA_Dal::factoryDO('data_intermediate_ad'); $doDSAH->day = $oDate->format('%Y-%m-%d'); $doDSAH->hour = 10; $doDSAH->ad_id = $bannerId; $doDSAH->impressions = $impressions; $doDSAH->clicks = $clicks; $doDSAH->conversions = $conversions; $dsahId = DataGenerator::generateOne($doDSAH); // Delivered 1 conversion in 1 day. So, expect to take 9 days to deliver remaining 9 $daysLeft = 9; $oExpirationDate = new Date(); $oExpirationDate->copy($oDate); $oExpirationDate->addSeconds($daysLeft * SECONDS_PER_DAY); $expected = array('estimatedExpiration' => $GLOBALS['strEstimated'] . ": " . $oExpirationDate->format('%d.%m.%Y') . " (" . $GLOBALS['strDaysLeft'] . ": " . $daysLeft . ")", 'campaignExpiration' => $GLOBALS['strNoExpiration']); $actual = $this->oDalCampaigns->getDaysLeftString($campaignId); $this->assertEqual($actual, $expected); // Case 2.4 // Test a triple limited campaign without expiration date // and with a estimated expiration date $totalImpressions = 1000; $totalClicks = 500; $totalConversions = 10; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->views = $totalImpressions; $doCampaigns->clicks = $totalClicks; $doCampaigns->conversions = $totalConversions; $aData = array('reportlastdate' => array('2007-04-03 18:39:45')); $dg = new DataGenerator(); $dg->setData('clients', $aData); $aCampaignIds = $dg->generate($doCampaigns, 1, true); $campaignId = $aCampaignIds[0]; // Link a banner to this campaign $doBanners = OA_Dal::factoryDO('banners'); $doBanners->campaignid = $campaignId; $doBanners->acls_updated = '2007-04-03 18:39:45'; $bannerId = DataGenerator::generateOne($doBanners); // Insert conversion delivery data occurring today $oDate = new Date(); $impressions = 50; $clicks = 5; $conversions = 1; $doDSAH = OA_Dal::factoryDO('data_intermediate_ad'); $doDSAH->day = $oDate->format('%Y-%m-%d'); $doDSAH->hour = 10; $doDSAH->ad_id = $bannerId; $doDSAH->impressions = $impressions; $doDSAH->clicks = $clicks; $doDSAH->conversions = $conversions; $dsahId = DataGenerator::generateOne($doDSAH); // Delivered 50 impressions in 1 day. So, expect to take 19 days to // deliver remaining 950 // Delivered 5 clicks in 1 day. So, expect to take 99 days to deliver // remaining 495 // Delivered 1 conversion in 1 day. So, expect to take 9 days to deliver // remaining 9 // The estimated expiration will be calucalated based on impression targets // or based on click targets or based on conversion targets (following this order). $daysLeft = 19; $oExpirationDate = new Date(); $oExpirationDate->copy($oDate); $oExpirationDate->addSeconds($daysLeft * SECONDS_PER_DAY); $expected = array('estimatedExpiration' => $GLOBALS['strEstimated'] . ": " . $oExpirationDate->format('%d.%m.%Y') . " (" . $GLOBALS['strDaysLeft'] . ": " . $daysLeft . ")", 'campaignExpiration' => $GLOBALS['strNoExpiration']); $actual = $this->oDalCampaigns->getDaysLeftString($campaignId); $this->assertEqual($actual, $expected); // Case 3 // Test a campaign with expiration date and without a estimated expiration date // Prepare a date 10 days in the future $daysLeft = 10; $oDate = new Date(); $oDate->setHour(23); $oDate->setMinute(59); $oDate->setSecond(59); $oDate->addSeconds($daysLeft * SECONDS_PER_DAY); $oDate->toUTC(); // Test an unlimited campaign which expires 10 days in the future $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->views = 0; $doCampaigns->clicks = 0; $doCampaigns->conversions = 0; $doCampaigns->expire_time = $oDate->getDate(DATE_FORMAT_ISO); $aData = array('reportlastdate' => array('2007-04-03 18:39:45')); $dg = new DataGenerator(); $dg->setData('clients', $aData); $aCampaignIds = $dg->generate($doCampaigns, 1, true); $campaignId = $aCampaignIds[0]; // Link a banner to this campaign $doBanners = OA_Dal::factoryDO('banners'); $doBanners->campaignid = $campaignId; $doBanners->acls_updated = '2007-04-03 18:39:45'; $bannerId = DataGenerator::generateOne($doBanners); $expected = array('estimatedExpiration' => $GLOBALS['strEstimated'] . ": " . $GLOBALS['strNoExpirationEstimation'], 'campaignExpiration' => $GLOBALS['strExpirationDate'] . ": " . $oDate->format('%d.%m.%Y') . " (" . $GLOBALS['strDaysLeft'] . ": " . $daysLeft . ")"); $actual = $this->oDalCampaigns->getDaysLeftString($campaignId); $this->assertEqual($actual, $expected); // Case 4 // Campaign with expiration date reached // Prepare a campaign with expiration date reached $daysExpired = 5; $oDate = new Date(); $oDate->setHour(23); $oDate->setMinute(59); $oDate->setSecond(59); $oDate->subtractSeconds($daysExpired * SECONDS_PER_DAY); $oDate->toUTC(); // Test an unlimited campaign which expired 5 days ago $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->views = 0; $doCampaigns->clicks = 0; $doCampaigns->conversions = 0; $doCampaigns->expire_time = $oDate->getDate(DATE_FORMAT_ISO); $aData = array('reportlastdate' => array('2007-04-03 18:39:45')); $dg = new DataGenerator(); $dg->setData('clients', $aData); $aCampaignIds = $dg->generate($doCampaigns, 1, true); $campaignId = $aCampaignIds[0]; // Link a banner to this campaign $doBanners = OA_Dal::factoryDO('banners'); $doBanners->campaignid = $campaignId; $doBanners->acls_updated = '2007-04-03 18:39:45'; $bannerId = DataGenerator::generateOne($doBanners); $expected = array('estimatedExpiration' => '', 'campaignExpiration' => $GLOBALS['strCampaignStop'] . ": " . $oDate->format('%d.%m.%Y') . " (" . $daysExpired . " " . $GLOBALS['strDaysAgo'] . ")"); $actual = $this->oDalCampaigns->getDaysLeftString($campaignId); $this->assertEqual($actual, $expected); // Case 5 // Campaign with expiration date and with estimated // expiration date minor than the expiration date // Prepare a date 25 days in the future $daysLeft = 25; $oDate = new Date(); $oDate->setHour(23); $oDate->setMinute(59); $oDate->setSecond(59); $oDate->addSeconds($daysLeft * SECONDS_PER_DAY); $oDate->toUTC(); $campaignExpiration = $GLOBALS['strExpirationDate'] . ": " . $oDate->format('%d.%m.%Y') . " (" . $GLOBALS['strDaysLeft'] . ": " . $daysLeft . ")"; $totalImpressions = 1000; $totalClicks = 500; $totalConversions = 10; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->expire_time = $oDate->getDate(DATE_FORMAT_ISO); $doCampaigns->views = $totalImpressions; $doCampaigns->clicks = $totalClicks; $doCampaigns->conversions = $totalConversions; $aData = array('reportlastdate' => array('2007-04-03 18:39:45')); $dg = new DataGenerator(); $dg->setData('clients', $aData); $aCampaignIds = $dg->generate($doCampaigns, 1, true); $campaignId = $aCampaignIds[0]; // Link a banner to this campaign $doBanners = OA_Dal::factoryDO('banners'); $doBanners->campaignid = $campaignId; $doBanners->acls_updated = '2007-04-03 18:39:45'; $bannerId = DataGenerator::generateOne($doBanners); // Insert conversion delivery data occurring today $oDate = new Date(); $impressions = 50; $clicks = 5; $conversions = 1; $doDSAH = OA_Dal::factoryDO('data_intermediate_ad'); $doDSAH->day = $oDate->format('%Y-%m-%d'); $doDSAH->hour = 10; $doDSAH->ad_id = $bannerId; $doDSAH->impressions = $impressions; $doDSAH->clicks = $clicks; $doDSAH->conversions = $conversions; $dsahId = DataGenerator::generateOne($doDSAH); // Delivered 50 impressions in 1 day. So, expect to take 19 days to // deliver remaining 950 // Delivered 5 clicks in 1 day. So, expect to take 99 days to deliver // remaining 495 // Delivered 1 conversion in 1 day. So, expect to take 9 days to deliver // remaining 9 // The estimated expiration will be calucalated based onimpression targets // or based on click targets or based on conversion targets (following this order). $daysLeft = 19; $oExpirationDate = new Date(); $oExpirationDate->copy($oDate); $oExpirationDate->addSeconds($daysLeft * SECONDS_PER_DAY); $expected = array('estimatedExpiration' => $GLOBALS['strEstimated'] . ": " . $oExpirationDate->format('%d.%m.%Y') . " (" . $GLOBALS['strDaysLeft'] . ": " . $daysLeft . ")", 'campaignExpiration' => $campaignExpiration); $actual = $this->oDalCampaigns->getDaysLeftString($campaignId); $this->assertEqual($actual, $expected); // Case 6 // Campaign with expiration date and with estimated // expiration date equals to the expiration date // Prepare a date 19 days in the future $daysLeft = 19; $oDate = new Date(); $oDate->setHour(23); $oDate->setMinute(59); $oDate->setSecond(59); $oDate->addSeconds($daysLeft * SECONDS_PER_DAY); $oDate->toUTC(); $campaignExpiration = $GLOBALS['strExpirationDate'] . ": " . $oDate->format('%d.%m.%Y') . " (" . $GLOBALS['strDaysLeft'] . ": " . $daysLeft . ")"; $totalImpressions = 1000; $totalClicks = 500; $totalConversions = 10; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->expire_time = $oDate->getDate(DATE_FORMAT_ISO); $doCampaigns->views = $totalImpressions; $doCampaigns->clicks = $totalClicks; $doCampaigns->conversions = $totalConversions; $aData = array('reportlastdate' => array('2007-04-03 18:39:45')); $dg = new DataGenerator(); $dg->setData('clients', $aData); $aCampaignIds = $dg->generate($doCampaigns, 1, true); $campaignId = $aCampaignIds[0]; // Link a banner to this campaign $doBanners = OA_Dal::factoryDO('banners'); $doBanners->campaignid = $campaignId; $doBanners->acls_updated = '2007-04-03 18:39:45'; $bannerId = DataGenerator::generateOne($doBanners); // Insert conversion delivery data occurring today $oDate = new Date(); $impressions = 50; $clicks = 5; $conversions = 1; $doDSAH = OA_Dal::factoryDO('data_intermediate_ad'); $doDSAH->day = $oDate->format('%Y-%m-%d'); $doDSAH->hour = 10; $doDSAH->ad_id = $bannerId; $doDSAH->impressions = $impressions; $doDSAH->clicks = $clicks; $doDSAH->conversions = $conversions; $dsahId = DataGenerator::generateOne($doDSAH); // Delivered 50 impressions in 1 day. So, expect to take 19 days to // deliver remaining 950 // Delivered 5 clicks in 1 day. So, expect to take 99 days to deliver // remaining 495 // Delivered 1 conversion in 1 day. So, expect to take 9 days to // deliver remaining 9 // The estimated expiration will be calucalated based on impression targets // or based on click targets or based on conversion targets (following this order). $daysLeft = 19; $oExpirationDate = new Date(); $oExpirationDate->copy($oDate); $oExpirationDate->addSeconds($daysLeft * SECONDS_PER_DAY); $expected = array('estimatedExpiration' => $GLOBALS['strEstimated'] . ": " . $oExpirationDate->format('%d.%m.%Y') . " (" . $GLOBALS['strDaysLeft'] . ": " . $daysLeft . ")", 'campaignExpiration' => $campaignExpiration); $actual = $this->oDalCampaigns->getDaysLeftString($campaignId); $this->assertEqual($actual, $expected); // Case 7 // Campaign with expiration date and with estimated // expiration date higher than the expiration date // Prepare a date 10 days in the future $daysLeft = 10; $oDate = new Date(); $oDate->setHour(23); $oDate->setMinute(59); $oDate->setSecond(59); $oDate->addSeconds($daysLeft * SECONDS_PER_DAY); $oDate->toUTC(); // Test a triple limited campaign with an expiration date 10 days // in the future $totalImpressions = 1000; $totalClicks = 500; $totalConversions = 10; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->views = $totalImpressions; $doCampaigns->clicks = $totalClicks; $doCampaigns->conversions = $totalConversions; $doCampaigns->expire_time = $oDate->getDate(DATE_FORMAT_ISO); $aData = array('reportlastdate' => array('2007-04-03 18:39:45')); $dg = new DataGenerator(); $dg->setData('clients', $aData); $aCampaignIds = $dg->generate($doCampaigns, 1, true); $campaignId = $aCampaignIds[0]; $campaignExpiration = $GLOBALS['strExpirationDate'] . ": " . $oDate->format('%d.%m.%Y') . " (" . $GLOBALS['strDaysLeft'] . ": " . $daysLeft . ")"; // Link a banner to this campaign $doBanners = OA_Dal::factoryDO('banners'); $doBanners->campaignid = $campaignId; $doBanners->acls_updated = '2007-04-03 18:39:45'; $bannerId = DataGenerator::generateOne($doBanners); // Insert conversion delivery data occurring today $oDate = new Date(); $impressions = 50; $clicks = 5; $conversions = 1; $doDSAH = OA_Dal::factoryDO('data_intermediate_ad'); $doDSAH->day = $oDate->format('%Y-%m-%d'); $doDSAH->hour = 10; $doDSAH->ad_id = $bannerId; $doDSAH->impressions = $impressions; $doDSAH->clicks = $clicks; $doDSAH->conversions = $conversions; $dsahId = DataGenerator::generateOne($doDSAH); // Expiration date is in 10 days // Delivered 50 impressions in 1 day. So, expect to take 19 days to // deliver remaining 950 // Delivered 5 clicks in 1 day. So, expect to take 99 days to // deliver remaining 495 // Delivered 1 conversion in 1 day. So, expect to take 9 days to // deliver remaining 9 // The estimated expiration will be calucalated based on impression targets // or based on click targets or based on conversion targets (following this order) $estimatedDaysLeft = 19; $oExpirationDate = new Date(); $oExpirationDate->copy($oDate); $oExpirationDate->addSeconds($estimatedDaysLeft * SECONDS_PER_DAY); // The extimated expiration is higher than the expiration set by the user // so the value of the extimated expiration will be null because is not a // relevant estimation because the campaign will expire before this estimation. $expected = array('estimatedExpiration' => '', 'campaignExpiration' => $campaignExpiration); $actual = $this->oDalCampaigns->getDaysLeftString($campaignId); $this->assertEqual($actual, $expected); }
// | http://www.opensource.org/licenses/bsd-license.php | // | If you did not receive a copy of the new BSDlicense and are unable | // | to obtain it through the world-wide-web, please send a note to | // | pear-dev@lists.php.net so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Author: Leandro Lucarella <*****@*****.**> | // +----------------------------------------------------------------------+ // // $Id$ // require_once 'Date.php'; require_once 'Date/Span.php'; $date = new Date(); $tmp = new Date($date); printf("Actual date: %s\n", $date->getDate(DATE_FORMAT_ISO)); $tmp->copy($date); $tmp->subtractSpan(new Date_Span('0:00:00:05')); printf("Subtracting 5 seconds: %s\n", $tmp->getDate(DATE_FORMAT_ISO)); $tmp->copy($date); $tmp->subtractSpan(new Date_Span('0:00:20:00')); printf("Subtracting 20 minutes: %s\n", $tmp->getDate(DATE_FORMAT_ISO)); $tmp->copy($date); $tmp->subtractSpan(new Date_Span('0:10:00:00')); printf("Subtracting 10 hours: %s\n", $tmp->getDate(DATE_FORMAT_ISO)); $tmp->copy($date); $tmp->subtractSpan(new Date_Span('3:00:00:00')); printf("Subtracting 3 days: %s\n", $tmp->getDate(DATE_FORMAT_ISO)); $tmp->copy($date); $tmp->subtractSpan(new Date_Span('3:10:20:05')); printf("Subtracting 3 days, 10 hours, 20 minutes and 5 seconds: %s\n", $tmp->getDate(DATE_FORMAT_ISO)); $tmp->copy($date);