2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
38 /*********************************************************************************
41 ********************************************************************************/
48 class Scheduler extends SugarBean {
54 var $modified_user_id;
57 var $modified_by_name;
71 var $intervalHumanReadable;
81 var $timeOutMins = 60;
82 // standard SugarBean attrs
83 var $table_name = "schedulers";
84 var $object_name = "schedulers";
85 var $module_dir = "Schedulers";
86 var $new_schema = true;
87 var $process_save_dates = true;
91 function Scheduler($init=true) {
97 $user->retrieve('1'); // Scheduler jobs run as Admin
103 ///////////////////////////////////////////////////////////////////////////
104 //// SCHEDULER HELPER FUNCTIONS
106 * executes Scheduled job
109 if(empty($this->job)) { // only execute when valid
110 $GLOBALS['log']->fatal('Scheduler tried to fire an empty job!!');
114 $exJob = explode('::', $this->job);
115 if(is_array($exJob)) {
116 // instantiate a new SchedulersJob object and prep it
119 $trackerManager = TrackerManager::getInstance();
120 $trackerManager->pause();
121 $job = new SchedulersJob();
122 $job->scheduler_id = $this->id;
123 $job->scheduler =& $this;
124 $job->execute_time = $job->handleDateFormat('now');
125 $jobId = $job->save();
126 $trackerManager->unPause();
127 $job->retrieve($jobId);
129 if($exJob[0] == 'function') {
130 $GLOBALS['log']->debug('----->Scheduler found a job of type FUNCTION');
131 require_once('modules/Schedulers/_AddJobsHere.php');
136 $GLOBALS['log']->debug('----->SchedulersJob firing '.$func);
138 $res = call_user_func($func);
147 } elseif($exJob[0] == 'url') {
148 if(function_exists('curl_init')) {
149 $GLOBALS['log']->debug('----->SchedulersJob found a job of type URL');
152 $GLOBALS['log']->debug('----->SchedulersJob firing URL job: '.$exJob[1]);
153 if($job->fireUrl($exJob[1])) {
171 * flushes dead or hung jobs
173 function flushDeadJobs() {
174 $GLOBALS['log']->debug('-----> Scheduler flushing dead jobs');
176 $lowerLimit = mktime(0, 0, 0, 1, 1, 2005); // jan 01, 2005, GMT-0
177 $now = strtotime(gmdate('Y-m-d H:i:s', strtotime('now'))); // this garbage to make sure we're getting comprable data to the DB output
179 $q = " SELECT s.id, s.name FROM schedulers s WHERE s.deleted=0 AND s.status = 'In Progress'";
180 $r = $this->db->query($q);
183 while($a = $this->db->fetchByAssoc($r)) {
184 $q2 = " SELECT st.id, st.execute_time FROM schedulers_times st
186 AND st.scheduler_id = '{$a['id']}'
187 ORDER BY st.execute_time DESC";
188 $r2 = $this->db->query($q2);
190 $a2 = $this->db->fetchByAssoc($r2); // we only care about the newest
192 $GLOBALS['log']->debug("-----> Scheduler found [ {$a['name']} ] 'In Progress' with most recent Execute Time at [ {$a2['execute_time']} GMT-0 ]");
194 $execTime = strtotime($a2['execute_time']);
195 if($execTime > $lowerLimit) {
196 if(($now - $execTime) >= (60 * $this->timeOutMins)) {
197 $GLOBALS['log']->info("-----> Scheduler found a dead Job. Flushing status and reseting Job");
198 $q3 = "UPDATE schedulers SET status = 'Active' WHERE id = '{$a['id']}'";
199 $this->db->query($q3);
201 $GLOBALS['log']->info("-----> Scheduler setting Job Instance status to 'failed'");
202 $q4 = "UPDATE schedulers_times SET status = 'failed' WHERE id = '{$a2['id']}';";
203 $this->db->query($q4);
205 $GLOBALS['log']->debug("-----> Scheduler will wait for job to complete - not past threshold of [ ".($this->timeOutMins * 60)."secs ] - timeDiff is ".($now - $execTime)." secs");
208 $GLOBALS['log']->fatal("-----> Scheduler got a bad execute time: [ {$a2['execute_time']} GMT-0 ]");
218 * calculates if a job is qualified to run
220 function fireQualified() {
221 if(empty($this->id)) { // execute only if we have an instance
222 $GLOBALS['log']->fatal('Scheduler called fireQualified() in a non-instance');
226 $now = gmdate('Y-m-d H:i', strtotime('now'));
227 $validTimes = $this->deriveDBDateTimes($this);
228 //_pp('now: '.$now); _pp($validTimes);
230 if(is_array($validTimes) && in_array($now, $validTimes)) {
231 $GLOBALS['log']->debug('----->Scheduler found valid job ('.$this->name.') for time GMT('.$now.')');
234 $GLOBALS['log']->debug('----->Scheduler did NOT find valid job ('.$this->name.') for time GMT('.$now.')');
247 * Checks if any jobs qualify to run at this moment
249 function checkPendingJobs2() {
250 $this->cleanJobLog();
251 $allSchedulers = $this->get_full_list('', 'schedulers.status=\'Active\'');
254 if(!empty($allSchedulers)) {
258 //// curl_setopt($ch, CURLOPT_FAILONERROR, true); // silent failure (code >300);
259 //// curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); // do not follow location(); inits - we always use the current
260 //// curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
261 //// curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false); // not thread-safe
262 // curl_setopt($ch, CURLOPT_TIMEOUT, 5); // never times out - bad idea?
263 // curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 5 secs for connect timeout
264 // curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); // open brand new conn
265 //// curl_setopt($ch, CURLOPT_NOPROGRESS, true); // do not have progress bar
266 //// curl_setopt($ch, CURLOPT_PORT, $_SERVER['SERVER_PORT']); // set port as reported by Server
267 //// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // most customers will not have Certificate Authority account
268 //// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // most customers will not have Certificate Authority account
269 // if(constant('PHP_VERSION') > '5.0.0') {
270 //// curl_setopt($ch, CURLOPT_NOSIGNAL, true); // ignore any cURL signals to PHP (for multi-threading)
272 // /* play with these options */
273 //// curl_setopt($ch, CURLOPT_HEADER, false); // do not return header info with result
274 //// curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // return into a variable to continue program execution
277 // foreach($allSchedulers as $focus) {
278 // if($focus->fireQualified()) {
279 // $GLOBALS['log']->debug('---------------------- GOT A JOB FOR CURL -----------');
280 // curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1/headdev/cronJob.php?id='.$focus->id); // set url
283 curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1/headdev/cronJob.php?id=82a9421a-9c60-111b-7212-4412394279e4'); // set url
284 curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1/headdev/cronJob.php?id=82a9421a-9c60-111b-7212-4412394279e4');
286 $result = curl_exec($ch);
287 $cInfo = curl_getinfo($ch);/* url,content_type,header_size,request_size,filetime,http_code,ssl_verify_result,total_time,namelookup_time,connect_time,pretransfer_time,size_upload,size_download,speed_download,speed_upload,download_content_length,upload_content_length,starttransfer_time,redirect_time */
290 if($cInfo['http_code'] < 400) {
291 $GLOBALS['log']->debug('----->Firing was successful: ('.$focus->id.') at');
292 $GLOBALS['log']->debug('----->WTIH RESULT: '.strip_tags($result).' AND '.strip_tags(print_r($cInfo)));
295 $GLOBALS['log']->fatal('Job errored: ('.$focus->id.')');
302 $GLOBALS['log']->debug('----->No Schedulers found');
337 * Checks if any jobs qualify to run at this moment
339 function checkPendingJobs() {
340 $this->cleanJobLog();
341 $allSchedulers = $this->get_full_list('', 'schedulers.status=\'Active\'');
343 $GLOBALS['log']->info('-----> Scheduler found [ '.count($allSchedulers).' ] ACTIVE jobs');
345 if(!empty($allSchedulers)) {
346 foreach($allSchedulers as $focus) {
347 if($focus->fireQualified()) {
349 $GLOBALS['log']->debug('----->Scheduler Job completed successfully');
351 $GLOBALS['log']->fatal('----->Scheduler Job FAILED');
356 $GLOBALS['log']->debug('----->No Schedulers found');
361 * This function takes a Scheduler object and uses its job_interval
362 * attribute to derive DB-standard datetime strings, as many as are
363 * qualified by its ranges. The times are from the time of calling the
366 * @param $focus Scheduler object
367 * @return $dateTimes array loaded with DB datetime strings derived from
368 * the job_interval attribute
369 * @return false If we the Scheduler is not in scope, return false.
371 function deriveDBDateTimes($focus) {
372 $GLOBALS['log']->debug('----->Schedulers->deriveDBDateTimes() got an object of type: '.$focus->object_name);
373 /* [min][hr][dates][mon][days] */
374 $dateTimes = array();
375 $ints = explode('::', str_replace(' ','',$focus->job_interval));
381 $today = getdate(gmmktime());
385 $GLOBALS['log']->debug('----->got * day');
387 } elseif(strstr($days, '*/')) {
388 // the "*/x" format is nonsensical for this field
389 // do basically nothing.
390 $theDay = str_replace('*/','',$days);
391 $dayName[] = $theDay;
392 } elseif($days != '*') { // got particular day(s)
393 if(strstr($days, ',')) {
394 $exDays = explode(',',$days);
395 foreach($exDays as $k1 => $dayGroup) {
396 if(strstr($dayGroup,'-')) {
397 $exDayGroup = explode('-', $dayGroup); // build up range and iterate through
398 for($i=$exDayGroup[0];$i<=$exDayGroup[1];$i++) {
401 } else { // individuals
402 $dayName[] = $dayGroup;
405 } elseif(strstr($days, '-')) {
406 $exDayGroup = explode('-', $days); // build up range and iterate through
407 for($i=$exDayGroup[0];$i<=$exDayGroup[1];$i++) {
414 // check the day to be in scope:
415 if(!in_array(($today['wday']+6)%7, $dayName)) {//$dayName starts from Monday, while $today['wday'] starts from Sunday
423 // derive months part
425 $GLOBALS['log']->debug('----->got * months');
426 } elseif(strstr($mons, '*/')) {
427 $mult = str_replace('*/','',$mons);
428 $startMon = date('m', strtotime($focus->date_time_start));
429 $startFrom = ($startMon % $mult);
431 for($i=$startFrom;$i<=12;$i+$mult) {
432 $compMons[] = $i+$mult;
435 // this month is not in one of the multiplier months
436 if(!in_array($today['mon'],$compMons)) {
439 } elseif($mons != '*') {
440 if(strstr($mons,',')) { // we have particular (groups) of months
441 $exMons = explode(',',$mons);
442 foreach($exMons as $k1 => $monGroup) {
443 if(strstr($monGroup, '-')) { // we have a range of months
444 $exMonGroup = explode('-',$monGroup);
445 for($i=$exMonGroup[0];$i<=$exMonGroup[1];$i++) {
449 $monName[] = $monGroup;
452 } elseif(strstr($mons, '-')) {
453 $exMonGroup = explode('-', $mons);
454 for($i=$exMonGroup[0];$i<=$exMonGroup[1];$i++) {
457 } else { // one particular month
461 // check that particular months are in scope
462 if(!in_array($today['mon'], $monName)) {
469 $GLOBALS['log']->debug('----->got * dates');
470 } elseif(strstr($dates, '*/')) {
471 $mult = str_replace('*/','',$dates);
472 $startDate = date('d', strtotime($focus->date_time_start));
473 $startFrom = ($startDate % $mult);
475 for($i=$startFrom; $i<=31; $i+$mult) {
476 $dateName[] = str_pad(($i+$mult),2,'0',STR_PAD_LEFT);
480 if(!in_array($today['mday'], $dateName)) {
483 } elseif($dates != '*') {
484 if(strstr($dates, ',')) {
485 $exDates = explode(',', $dates);
486 foreach($exDates as $k1 => $dateGroup) {
487 if(strstr($dateGroup, '-')) {
488 $exDateGroup = explode('-', $dateGroup);
489 for($i=$exDateGroup[0];$i<=$exDateGroup[1];$i++) {
493 $dateName[] = $dateGroup;
496 } elseif(strstr($dates, '-')) {
497 $exDateGroup = explode('-', $dates);
498 for($i=$exDateGroup[0];$i<=$exDateGroup[1];$i++) {
502 $dateName[] = $dates;
505 // check that dates are in scope
506 if(!in_array($today['mday'], $dateName)) {
512 //$currentHour = gmdate('G');
513 //$currentHour = date('G', strtotime('00:00'));
515 $GLOBALS['log']->debug('----->got * hours');
516 for($i=0;$i<24; $i++) {
519 } elseif(strstr($hrs, '*/')) {
520 $mult = str_replace('*/','',$hrs);
521 for($i=0; $i<24; $i) { // weird, i know
525 } elseif($hrs != '*') {
526 if(strstr($hrs, ',')) {
527 $exHrs = explode(',',$hrs);
528 foreach($exHrs as $k1 => $hrGroup) {
529 if(strstr($hrGroup, '-')) {
530 $exHrGroup = explode('-', $hrGroup);
531 for($i=$exHrGroup[0];$i<=$exHrGroup[1];$i++) {
535 $hrName[] = $hrGroup;
538 } elseif(strstr($hrs, '-')) {
539 $exHrs = explode('-', $hrs);
540 for($i=$exHrs[0];$i<=$exHrs[1];$i++) {
549 //$currentMin = date('i');
550 $currentMin = date('i', strtotime($this->date_time_start));
551 if(substr($currentMin, 0, 1) == '0') {
552 $currentMin = substr($currentMin, 1, 1);
555 $GLOBALS['log']->debug('----->got * mins');
556 for($i=0; $i<60; $i++) {
557 if(($currentMin + $i) > 59) {
558 $minName[] = ($i + $currentMin - 60);
560 $minName[] = ($i+$currentMin);
563 } elseif(strstr($mins,'*/')) {
564 $mult = str_replace('*/','',$mins);
565 $startMin = date('i',strtotime($focus->date_time_start));
566 $startFrom = ($startMin % $mult);
567 for($i=$startFrom; $i<=59; $i) {
568 if(($currentMin + $i) > 59) {
569 $minName[] = ($i + $currentMin - 60);
571 $minName[] = ($i+$currentMin);
576 } elseif($mins != '*') {
577 if(strstr($mins, ',')) {
578 $exMins = explode(',',$mins);
579 foreach($exMins as $k1 => $minGroup) {
580 if(strstr($minGroup, '-')) {
581 $exMinGroup = explode('-', $minGroup);
582 for($i=$exMinGroup[0]; $i<=$exMinGroup[1]; $i++) {
586 $minName[] = $minGroup;
589 } elseif(strstr($mins, '-')) {
590 $exMinGroup = explode('-', $mins);
591 for($i=$exMinGroup[0]; $i<=$exMinGroup[1]; $i++) {
599 // prep some boundaries - these are not in GMT b/c gmt is a 24hour period, possibly bridging 2 local days
600 if(empty($focus->time_from) && empty($focus->time_to) ) {
602 $timeToTs = strtotime('+1 day');
604 $timeFromTs = strtotime($focus->time_from); // these are now GMT (timestamps are all GMT)
605 $timeToTs = strtotime($focus->time_to); // see above
606 if($timeFromTs > $timeToTs) { // we've crossed into the next day
607 $timeToTs = strtotime('+1 day '. $focus->time_to); // also in GMT
612 if(empty($focus->last_run)) {
615 $lastRunTs = strtotime($focus->last_run . ' UTC');
620 * initialize return array
622 $validJobTime = array();
625 $timeStartTs = strtotime($focus->date_time_start . ' UTC');
626 if(!empty($focus->date_time_end)) { // do the same for date_time_end if not empty
627 $dateTimeEnd = $focus->date_time_end;
629 $dateTimeEnd = gmdate('Y-m-d H:i:s', strtotime('+1 day'));
630 // $dateTimeEnd = '2020-12-31 23:59:59'; // if empty, set it to something ridiculous
632 $timeEndTs = strtotime($dateTimeEnd.' UTC'); // GMT end timestamp if necessary
634 /*_pp('hours:'); _pp($hrName);_pp('mins:'); _pp($minName);*/
637 // _pp('currentHour: '. $currentHour);
638 // _pp('timeStartTs: '.date('r',$timeStartTs));
639 // _pp('timeFromTs: '.date('r',$timeFromTs));
640 // _pp('timeEndTs: '.date('r',$timeEndTs));
641 // _pp('timeToTs: '.date('r',$timeToTs));
642 // _pp('mktime: '.date('r',mktime()));
643 // _pp('timeLastRun: '.date('r',$lastRunTs));
650 foreach($hrName as $kHr=>$hr) {
652 foreach($minName as $kMin=>$min) {
653 if($hourSeen == 25) {
654 $theDate = date('Y-m-d', strtotime('+1 day'));
656 $theDate = date('Y-m-d');
659 $tsGmt = strtotime($theDate.' '.str_pad($hr,2,'0',STR_PAD_LEFT).":".str_pad($min,2,'0',STR_PAD_LEFT).":00"); // this is LOCAL
661 if( $tsGmt >= $timeStartTs ) { // start is greater than the date specified by admin
662 if( $tsGmt >= $timeFromTs ) { // start is greater than the time_to spec'd by admin
663 if($tsGmt > $lastRunTs) { // start from last run, last run should not be included
664 if( $tsGmt <= $timeEndTs ) { // this is taken care of by the initial query - start is less than the date spec'd by admin
665 if( $tsGmt <= $timeToTs ) { // start is less than the time_to
666 $validJobTime[] = gmdate('Y-m-d H:i', $tsGmt);
668 //_pp('Job Time is NOT smaller that TimeTO: '.$tsGmt .'<='. $timeToTs);
671 //_pp('Job Time is NOT smaller that DateTimeEnd: '.date('Y-m-d H:i:s',$tsGmt) .'<='. $dateTimeEnd); //_pp( $tsGmt .'<='. $timeEndTs );
675 //_pp('Job Time is NOT bigger that TimeFrom: '.$tsGmt .'>='. $timeFromTs);
678 //_pp('Job Time is NOT Bigger than DateTimeStart: '.date('Y-m-d H:i',$tsGmt) .'>='. $dateTimeStart);
682 //_ppd($validJobTime);
683 // need ascending order to compare oldest time to last_run
686 * If "Execute If Missed bit is set
688 if($focus->catch_up == 1) {
689 if($focus->last_run == null) {
691 $validJobTime[] = gmdate('Y-m-d H:i', strtotime('now'));
693 // determine what the interval in min/hours is
694 // see if last_run is in it
696 $now = gmdate('Y-m-d H:i', strtotime('now'));
697 if(!empty($validJobTime) && ($focus->last_run < $validJobTime[0]) && ($now > $validJobTime[0])) {
698 // cn: empty() bug 5914;
699 //if(!empty) should be checked, becasue if a scheduler is defined to run every day 4pm, then after 4pm, and it runs as 4pm, the $validJobTime will be empty, and it should not catch up
700 //if $focus->last_run is the the day before yesterday, it should run yesterday and tomorrow, but it hadn't run yesterday, then it should catch up today. But today is already filtered out when doing date check before. The catch up will not work on this occasion. If the scheduler runs at least one time on each day, I think this bug can be avoided.
701 $validJobTime[] = $now;
705 return $validJobTime;
708 function handleIntervalType($type, $value, $mins, $hours) {
710 /* [0]:min [1]:hour [2]:day of month [3]:month [4]:day of week */
711 $days = array ( 0 => $mod_strings['LBL_MON'],
712 1 => $mod_strings['LBL_TUE'],
713 2 => $mod_strings['LBL_WED'],
714 3 => $mod_strings['LBL_THU'],
715 4 => $mod_strings['LBL_FRI'],
716 5 => $mod_strings['LBL_SAT'],
717 6 => $mod_strings['LBL_SUN'],
718 '*' => $mod_strings['LBL_ALL']);
723 return trim($mod_strings['LBL_ON_THE']).$mod_strings['LBL_HOUR_SING'];
724 } elseif(!preg_match('/[^0-9]/', $hours) && !preg_match('/[^0-9]/', $value)) {
727 } elseif(preg_match('/\*\//', $value)) {
728 $value = str_replace('*/','',$value);
729 return $value.$mod_strings['LBL_MINUTES'];
730 } elseif(!preg_match('[^0-9]', $value)) {
731 return $mod_strings['LBL_ON_THE'].$value.$mod_strings['LBL_MIN_MARK'];
736 global $current_user;
737 if(preg_match('/\*\//', $value)) { // every [SOME INTERVAL] hours
738 $value = str_replace('*/','',$value);
739 return $value.$mod_strings['LBL_HOUR'];
740 } elseif(preg_match('/[^0-9]/', $mins)) { // got a range, or multiple of mins, so we return an 'Hours' label
742 } else { // got a "minutes" setting, so it will be at some o'clock.
743 $datef = $current_user->getUserDateTimePreferences();
744 return date($datef['time'], strtotime($value.':'.str_pad($mins, 2, '0', STR_PAD_LEFT)));
746 case 2: // day of month
747 if(preg_match('/\*/', $value)) {
750 return date('jS', strtotime('December '.$value));
754 return date('F', strtotime('2005-'.$value.'-01'));
755 case 4: // days of week
756 return $days[$value];
758 return 'bad'; // no condition to touch this branch
762 function setIntervalHumanReadable() {
763 global $current_user;
766 /* [0]:min [1]:hour [2]:day of month [3]:month [4]:day of week */
767 $ints = $this->intervalParsed;
768 $intVal = array('-', ',');
769 $intSub = array($mod_strings['LBL_RANGE'], $mod_strings['LBL_AND']);
770 $intInt = array(0 => $mod_strings['LBL_MINS'], 1 => $mod_strings['LBL_HOUR']);
774 foreach($ints['raw'] as $key => $interval) {
775 if($tempInt != $iteration) {
778 $iteration = $tempInt;
780 if($interval != '*' && $interval != '*/1') {
781 if(false !== strpos($interval, ',')) {
782 $exIndiv = explode(',', $interval);
783 foreach($exIndiv as $val) {
784 if(false !== strpos($val, '-')) {
785 $exRange = explode('-', $val);
786 foreach($exRange as $valRange) {
788 $tempInt .= $mod_strings['LBL_AND'];
790 $tempInt .= $this->handleIntervalType($key, $valRange, $ints['raw'][0], $ints['raw'][1]);
792 } elseif($tempInt != $iteration) {
793 $tempInt .= $mod_strings['LBL_AND'];
795 $tempInt .= $this->handleIntervalType($key, $val, $ints['raw'][0], $ints['raw'][1]);
797 } elseif(false !== strpos($interval, '-')) {
798 $exRange = explode('-', $interval);
799 $tempInt .= $mod_strings['LBL_FROM'];
802 foreach($exRange as $val) {
803 if($tempInt == $check) {
804 $tempInt .= $this->handleIntervalType($key, $val, $ints['raw'][0], $ints['raw'][1]);
805 $tempInt .= $mod_strings['LBL_RANGE'];
808 $tempInt .= $this->handleIntervalType($key, $val, $ints['raw'][0], $ints['raw'][1]);
812 } elseif(false !== strpos($interval, '*/')) {
813 $tempInt .= $mod_strings['LBL_EVERY'];
814 $tempInt .= $this->handleIntervalType($key, $interval, $ints['raw'][0], $ints['raw'][1]);
816 $tempInt .= $this->handleIntervalType($key, $interval, $ints['raw'][0], $ints['raw'][1]);
822 $this->intervalHumanReadable = $mod_strings['LBL_OFTEN'];
824 $tempInt = trim($tempInt);
825 if(';' == substr($tempInt, (strlen($tempInt)-1), strlen($tempInt))) {
826 $tempInt = substr($tempInt, 0, (strlen($tempInt)-1));
828 $this->intervalHumanReadable = $tempInt;
833 /* take an integer and return its suffix */
834 function setStandardArraysAttributes() {
836 global $app_list_strings; // using from month _dom list
838 $suffArr = array('','st','nd','rd');
839 for($i=1; $i<32; $i++) {
840 if($i > 3 && $i < 21) {
841 $this->suffixArray[$i] = $i."th";
842 } elseif (substr($i,-1,1) < 4 && substr($i,-1,1) > 0) {
843 $this->suffixArray[$i] = $i.$suffArr[substr($i,-1,1)];
845 $this->suffixArray[$i] = $i."th";
847 $this->datesArray[$i] = $i;
850 $this->dayInt = array('*',1,2,3,4,5,6,7);
851 $this->dayLabel = array('*',$mod_strings['LBL_MON'],$mod_strings['LBL_TUE'],$mod_strings['LBL_WED'],$mod_strings['LBL_THU'],$mod_strings['LBL_FRI'],$mod_strings['LBL_SAT'],$mod_strings['LBL_SUN']);
852 $this->monthsInt = array(0,1,2,3,4,5,6,7,8,9,10,11,12);
853 $this->monthsLabel = $app_list_strings['dom_cal_month_long'];
854 $this->metricsVar = array("*", "/", "-", ",");
855 $this->metricsVal = array(' every ','',' thru ',' and ');
859 * takes the serialized interval string and renders it into an array
861 function parseInterval() {
863 $ws = array(' ', '\r','\t');
864 $blanks = array('','','');
866 $intv = $this->job_interval;
867 $rawValues = explode('::', $intv);
868 $rawProcessed = str_replace($ws,$blanks,$rawValues); // strip all whitespace
870 $hours = $rawValues[1].':::'.$rawValues[0];
871 $months = $rawValues[3].':::'.$rawValues[2];
873 $intA = array ( 'raw' => $rawProcessed,
878 $this->intervalParsed = $intA;
882 * soft-deletes all job logs older than 24 hours
884 function cleanJobLog() {
885 $this->db->query('DELETE FROM schedulers_times WHERE date_entered < '.db_convert('\''.gmdate($GLOBALS['timedate']->get_db_date_time_format(), strtotime('-24 hours')).'\'', 'datetime').'');
889 * checks for cURL libraries
891 function checkCurl() {
894 if(!function_exists('curl_init')) {
896 <table cellpadding="0" cellspacing="0" width="100%" border="0" class="list view">
898 <th width="25%" colspan="2"><slot>
899 '.$mod_strings['LBL_WARN_CURL_TITLE'].'
902 <tr class="oddListRowS1" >
903 <td scope="row" valign=TOP width="20%"><slot>
904 '.$mod_strings['LBL_WARN_CURL'].'
905 <td scope="row" valign=TOP width="80%"><slot>
906 <span class=error>'.$mod_strings['LBL_WARN_NO_CURL'].'</span>
914 function displayCronInstructions() {
916 global $sugar_config;
918 if (!isset($_SERVER['Path'])) {
919 $_SERVER['Path'] = getenv('Path');
922 if(isset($_SERVER['Path']) && !empty($_SERVER['Path'])) { // IIS IUSR_xxx may not have access to Path or it is not set
923 if(!strpos($_SERVER['Path'], 'php')) {
924 $error = '<em>'.$mod_strings['LBL_NO_PHP_CLI'].'</em>';
928 if(isset($_SERVER['Path']) && !empty($_SERVER['Path'])) { // some Linux servers do not make this available
929 if(!strpos($_SERVER['PATH'], 'php')) {
930 $error = '<em>'.$mod_strings['LBL_NO_PHP_CLI'].'</em>';
940 <table cellpadding="0" cellspacing="0" width="100%" border="0" class="list view">
943 '.$mod_strings['LBL_CRON_INSTRUCTIONS_WINDOWS'].'
946 <tr class="evenListRowS1">
947 <td scope="row" valign="top" width="70%"><slot>
948 '.$mod_strings['LBL_CRON_WINDOWS_DESC'].'<br>
949 <b>cd '.realpath('./').'<br>
950 php.exe -f cron.php</b>
957 <table cellpadding="0" cellspacing="0" width="100%" border="0" class="list view">
960 '.$mod_strings['LBL_CRON_INSTRUCTIONS_LINUX'].'
964 <td scope="row" valign=TOP class="oddListRowS1" bgcolor="#fdfdfd" width="70%"><slot>
965 '.$mod_strings['LBL_CRON_LINUX_DESC'].'<br>
966 <b>* * * * *
967 cd '.realpath('./').'; php -f cron.php > /dev/null 2>&1</b>
976 * Archives schedulers of the same functionality, then instantiates new
979 function rebuildDefaultSchedulers() {
981 // truncate scheduler-related tables
982 $this->db->query('DELETE FROM schedulers');
983 $this->db->query('DELETE FROM schedulers_times');
986 $sched3 = new Scheduler();
987 $sched3->name = $mod_strings['LBL_OOTB_TRACKER'];
988 $sched3->job = 'function::trimTracker';
989 $sched3->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1);
990 $sched3->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59);
991 $sched3->job_interval = '0::2::1::*::*';
992 $sched3->status = 'Active';
993 $sched3->created_by = '1';
994 $sched3->modified_user_id = '1';
995 $sched3->catch_up = '1';
997 $sched4 = new Scheduler();
998 $sched4->name = $mod_strings['LBL_OOTB_IE'];
999 $sched4->job = 'function::pollMonitoredInboxes';
1000 $sched4->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1);
1001 $sched4->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59);
1002 $sched4->job_interval = '*::*::*::*::*';
1003 $sched4->status = 'Active';
1004 $sched4->created_by = '1';
1005 $sched4->modified_user_id = '1';
1006 $sched4->catch_up = '0';
1009 $sched5 = new Scheduler();
1010 $sched5->name = $mod_strings['LBL_OOTB_BOUNCE'];
1011 $sched5->job = 'function::pollMonitoredInboxesForBouncedCampaignEmails';
1012 $sched5->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1);
1013 $sched5->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59);
1014 $sched5->job_interval = '0::2-6::*::*::*';
1015 $sched5->status = 'Active';
1016 $sched5->created_by = '1';
1017 $sched5->modified_user_id = '1';
1018 $sched5->catch_up = '1';
1021 $sched6 = new Scheduler();
1022 $sched6->name = $mod_strings['LBL_OOTB_CAMPAIGN'];
1023 $sched6->job = 'function::runMassEmailCampaign';
1024 $sched6->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1);
1025 $sched6->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59);
1026 $sched6->job_interval = '0::2-6::*::*::*';
1027 $sched6->status = 'Active';
1028 $sched6->created_by = '1';
1029 $sched6->modified_user_id = '1';
1030 $sched6->catch_up = '1';
1034 $sched7 = new Scheduler();
1035 $sched7->name = $mod_strings['LBL_OOTB_PRUNE'];
1036 $sched7->job = 'function::pruneDatabase';
1037 $sched7->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1);
1038 $sched7->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59);
1039 $sched7->job_interval = '0::4::1::*::*';
1040 $sched7->status = 'Inactive';
1041 $sched7->created_by = '1';
1042 $sched7->modified_user_id = '1';
1043 $sched7->catch_up = '0';
1052 //// END SCHEDULER HELPER FUNCTIONS
1053 ///////////////////////////////////////////////////////////////////////////
1056 ///////////////////////////////////////////////////////////////////////////
1057 //// STANDARD SUGARBEAN OVERRIDES
1059 * function overrides the one in SugarBean.php
1061 function create_export_query($order_by, $where, $show_deleted = 0) {
1062 return $this->create_new_list_query($order_by, $where,array(),array(), $show_deleted = 0);
1066 * function overrides the one in SugarBean.php
1070 * function overrides the one in SugarBean.php
1072 function fill_in_additional_list_fields() {
1073 $this->fill_in_additional_detail_fields();
1077 * function overrides the one in SugarBean.php
1079 function fill_in_additional_detail_fields() {
1083 * function overrides the one in SugarBean.php
1085 function get_list_view_data(){
1086 global $mod_strings;
1087 $temp_array = $this->get_list_view_array();
1088 $temp_array["ENCODED_NAME"]=$this->name;
1089 $this->parseInterval();
1090 $this->setIntervalHumanReadable();
1091 $temp_array['JOB_INTERVAL'] = $this->intervalHumanReadable;
1092 if($this->date_time_end == '2020-12-31 23:59' || $this->date_time_end == '') {
1093 $temp_array['DATE_TIME_END'] = $mod_strings['LBL_PERENNIAL'];
1095 $this->created_by_name = get_assigned_user_name($this->created_by);
1096 $this->modified_by_name = get_assigned_user_name($this->modified_user_id);
1102 * returns the bean name - overrides SugarBean's
1104 function get_summary_text() {
1107 //// END STANDARD SUGARBEAN OVERRIDES
1108 ///////////////////////////////////////////////////////////////////////////
1109 } // end class definition