]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/Schedulers/Scheduler.php
Release 6.5.6
[Github/sugarcrm.git] / modules / Schedulers / Scheduler.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM Community Edition is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
6  * 
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.
13  * 
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
17  * details.
18  * 
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
22  * 02110-1301 USA.
23  * 
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.
26  * 
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.
30  * 
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  ********************************************************************************/
37
38 require_once 'modules/SchedulersJobs/SchedulersJob.php';
39
40 class Scheduler extends SugarBean {
41         // table columns
42         var $id;
43         var $deleted;
44         var $date_entered;
45         var $date_modified;
46         var $modified_user_id;
47         var $created_by;
48         var $created_by_name;
49         var $modified_by_name;
50         var $name;
51         var $job;
52         var $date_time_start;
53         var $date_time_end;
54         var $job_interval;
55         var $time_from;
56         var $time_to;
57         var $last_run;
58         var $status;
59         var $catch_up;
60         // object attributes
61         var $user;
62         var $intervalParsed;
63         var $intervalHumanReadable;
64         var $metricsVar;
65         var $metricsVal;
66         var $dayInt;
67         var $dayLabel;
68         var $monthsInt;
69         var $monthsLabel;
70         var $suffixArray;
71         var $datesArray;
72         var $scheduledJobs;
73         var $timeOutMins = 60;
74         // standard SugarBean attrs
75         var $table_name                         = "schedulers";
76         var $object_name                        = "Scheduler";
77         var $module_dir                         = "Schedulers";
78         var $new_schema                         = true;
79         var $process_save_dates         = true;
80         var $order_by;
81
82         public static $job_strings;
83
84     public function __construct($init=true)
85     {
86         parent::SugarBean();
87         $job = new SchedulersJob();
88         $this->job_queue_table = $job->table_name;
89     }
90
91     protected function getUser()
92     {
93         if(empty($this->user)) {
94             $this->user = Scheduler::initUser();
95         }
96         return $this->user;
97     }
98
99     /**
100      * Function returns an Admin user for running Schedulers or false if no admin users are present in the system
101      * (which means the Scheduler Jobs which need admin rights will fail to execute)
102      */
103     public static function initUser()
104     {
105         $user = new User();
106         $db = DBManagerFactory::getInstance();
107         
108         //Check is default admin exists
109         $adminId = $db->getOne(
110             'SELECT id FROM users WHERE id = ' . $db->quoted('1') . ' AND is_admin = 1 AND deleted = 0 AND status = ' . $db->quoted('Active'),
111             true,
112             'Error retrieving Admin account info'
113         );
114         
115         if ($adminId === false) {// Retrieve another admin if default admin doesn't exist
116             $adminId = $db->getOne(
117                 'SELECT id FROM users WHERE is_admin = 1 AND deleted = 0 AND status = ' . $db->quoted('Active'),
118                 true,
119                 'Error retrieving Admin account info'
120             );
121             if ($adminId) {// Get admin user
122                 $user->retrieve($adminId);
123             } else {// Return false and log error
124                 $GLOBALS['log']->fatal('No Admin account found!');
125                 return false;
126             }
127         } else {// Scheduler jobs run as default Admin
128             $user->retrieve('1'); 
129         }
130         return $user;
131     }
132
133
134         ///////////////////////////////////////////////////////////////////////////
135         ////    SCHEDULER HELPER FUNCTIONS
136
137         /**
138          * calculates if a job is qualified to run
139          */
140         public function fireQualified()
141         {
142                 if(empty($this->id)) { // execute only if we have an instance
143                         $GLOBALS['log']->fatal('Scheduler called fireQualified() in a non-instance');
144                         return false;
145                 }
146
147                 $now = TimeDate::getInstance()->getNow();
148                 $now = $now->setTime($now->hour, $now->min, "00")->asDb();
149                 $validTimes = $this->deriveDBDateTimes($this);
150
151                 if(is_array($validTimes) && in_array($now, $validTimes)) {
152                         $GLOBALS['log']->debug('----->Scheduler found valid job ('.$this->name.') for time GMT('.$now.')');
153                         return true;
154                 } else {
155                         $GLOBALS['log']->debug('----->Scheduler did NOT find valid job ('.$this->name.') for time GMT('.$now.')');
156                         return false;
157                 }
158         }
159
160         /**
161          * Create a job from this scheduler
162          * @return SchedulersJob
163          */
164         public function createJob()
165         {
166             $job = new SchedulersJob();
167             $job->scheduler_id = $this->id;
168         $job->name = $this->name;
169         $job->execute_time = $GLOBALS['timedate']->nowDb();
170         $job->assigned_user_id = $this->getUser()->id;
171         $job->target = $this->job;
172         return $job;
173         }
174
175         /**
176          * Checks if any jobs qualify to run at this moment
177          * @param SugarJobQueue $queue
178          */
179         public function checkPendingJobs($queue)
180         {
181                 $allSchedulers = $this->get_full_list('', "schedulers.status='Active' AND NOT EXISTS(SELECT id FROM {$this->job_queue_table} WHERE scheduler_id=schedulers.id AND status!='".SchedulersJob::JOB_STATUS_DONE."')");
182
183                 $GLOBALS['log']->info('-----> Scheduler found [ '.count($allSchedulers).' ] ACTIVE jobs');
184
185                 if(!empty($allSchedulers)) {
186                         foreach($allSchedulers as $focus) {
187                                 if($focus->fireQualified()) {
188                                     $job = $focus->createJob();
189                                     $queue->submitJob($job, $this->getUser());
190                                 }
191                         }
192                 } else {
193                         $GLOBALS['log']->debug('----->No Schedulers found');
194                 }
195         }
196
197         /**
198          * This function takes a Scheduler object and uses its job_interval
199          * attribute to derive DB-standard datetime strings, as many as are
200          * qualified by its ranges.  The times are from the time of calling the
201          * script.
202          *
203          * @param       $focus          Scheduler object
204          * @return      $dateTimes      array loaded with DB datetime strings derived from
205          *                                              the      job_interval attribute
206          * @return      false           If we the Scheduler is not in scope, return false.
207          */
208         function deriveDBDateTimes($focus)
209         {
210         global $timedate;
211                 $GLOBALS['log']->debug('----->Schedulers->deriveDBDateTimes() got an object of type: '.$focus->object_name);
212                 /* [min][hr][dates][mon][days] */
213                 $dateTimes = array();
214                 $ints   = explode('::', str_replace(' ','',$focus->job_interval));
215                 $days   = $ints[4];
216                 $mons   = $ints[3];
217                 $dates  = $ints[2];
218                 $hrs    = $ints[1];
219                 $mins   = $ints[0];
220                 $today  = getdate($timedate->getNow()->ts);
221
222                 // derive day part
223                 if($days == '*') {
224                         $GLOBALS['log']->debug('----->got * day');
225
226                 } elseif(strstr($days, '*/')) {
227                         // the "*/x" format is nonsensical for this field
228                         // do basically nothing.
229                         $theDay = str_replace('*/','',$days);
230                         $dayName[] = $theDay;
231                 } elseif($days != '*') { // got particular day(s)
232                         if(strstr($days, ',')) {
233                                 $exDays = explode(',',$days);
234                                 foreach($exDays as $k1 => $dayGroup) {
235                                         if(strstr($dayGroup,'-')) {
236                                                 $exDayGroup = explode('-', $dayGroup); // build up range and iterate through
237                                                 for($i=$exDayGroup[0];$i<=$exDayGroup[1];$i++) {
238                                                         $dayName[] = $i;
239                                                 }
240                                         } else { // individuals
241                                                 $dayName[] = $dayGroup;
242                                         }
243                                 }
244                         } elseif(strstr($days, '-')) {
245                                 $exDayGroup = explode('-', $days); // build up range and iterate through
246                                 for($i=$exDayGroup[0];$i<=$exDayGroup[1];$i++) {
247                                         $dayName[] = $i;
248                                 }
249                         } else {
250                                 $dayName[] = $days;
251                         }
252
253                         // check the day to be in scope:
254                         if(!in_array($today['wday'], $dayName)) {
255                                 return false;
256                         }
257                 } else {
258                         return false;
259                 }
260
261
262                 // derive months part
263                 if($mons == '*') {
264                         $GLOBALS['log']->debug('----->got * months');
265                 } elseif(strstr($mons, '*/')) {
266                         $mult = str_replace('*/','',$mons);
267                         $startMon = $timedate->fromDb(date_time_start)->month;
268                         $startFrom = ($startMon % $mult);
269
270                         for($i=$startFrom;$i<=12;$i+$mult) {
271                                 $compMons[] = $i+$mult;
272                                 $i += $mult;
273                         }
274                         // this month is not in one of the multiplier months
275                         if(!in_array($today['mon'],$compMons)) {
276                                 return false;
277                         }
278                 } elseif($mons != '*') {
279                         if(strstr($mons,',')) { // we have particular (groups) of months
280                                 $exMons = explode(',',$mons);
281                                 foreach($exMons as $k1 => $monGroup) {
282                                         if(strstr($monGroup, '-')) { // we have a range of months
283                                                 $exMonGroup = explode('-',$monGroup);
284                                                 for($i=$exMonGroup[0];$i<=$exMonGroup[1];$i++) {
285                                                         $monName[] = $i;
286                                                 }
287                                         } else {
288                                                 $monName[] = $monGroup;
289                                         }
290                                 }
291                         } elseif(strstr($mons, '-')) {
292                                 $exMonGroup = explode('-', $mons);
293                                 for($i=$exMonGroup[0];$i<=$exMonGroup[1];$i++) {
294                                         $monName[] = $i;
295                                 }
296                         } else { // one particular month
297                                 $monName[] = $mons;
298                         }
299
300                         // check that particular months are in scope
301                         if(!in_array($today['mon'], $monName)) {
302                                 return false;
303                         }
304                 }
305
306                 // derive dates part
307                 if($dates == '*') {
308                         $GLOBALS['log']->debug('----->got * dates');
309                 } elseif(strstr($dates, '*/')) {
310                         $mult = str_replace('*/','',$dates);
311                         $startDate = $timedate->fromDb($focus->date_time_start)->day;
312                         $startFrom = ($startDate % $mult);
313
314                         for($i=$startFrom; $i<=31; $i+$mult) {
315                                 $dateName[] = str_pad(($i+$mult),2,'0',STR_PAD_LEFT);
316                                 $i += $mult;
317                         }
318
319                         if(!in_array($today['mday'], $dateName)) {
320                                 return false;
321                         }
322                 } elseif($dates != '*') {
323                         if(strstr($dates, ',')) {
324                                 $exDates = explode(',', $dates);
325                                 foreach($exDates as $k1 => $dateGroup) {
326                                         if(strstr($dateGroup, '-')) {
327                                                 $exDateGroup = explode('-', $dateGroup);
328                                                 for($i=$exDateGroup[0];$i<=$exDateGroup[1];$i++) {
329                                                         $dateName[] = $i;
330                                                 }
331                                         } else {
332                                                 $dateName[] = $dateGroup;
333                                         }
334                                 }
335                         } elseif(strstr($dates, '-')) {
336                                 $exDateGroup = explode('-', $dates);
337                                 for($i=$exDateGroup[0];$i<=$exDateGroup[1];$i++) {
338                                         $dateName[] = $i;
339                                 }
340                         } else {
341                                 $dateName[] = $dates;
342                         }
343
344                         // check that dates are in scope
345                         if(!in_array($today['mday'], $dateName)) {
346                                 return false;
347                         }
348                 }
349
350                 // derive hours part
351                 //$currentHour = gmdate('G');
352                 //$currentHour = date('G', strtotime('00:00'));
353                 if($hrs == '*') {
354                         $GLOBALS['log']->debug('----->got * hours');
355                         for($i=0;$i<24; $i++) {
356                                 $hrName[]=$i;
357                         }
358                 } elseif(strstr($hrs, '*/')) {
359                         $mult = str_replace('*/','',$hrs);
360                         for($i=0; $i<24; $i) { // weird, i know
361                                 $hrName[]=$i;
362                                 $i += $mult;
363                         }
364                 } elseif($hrs != '*') {
365                         if(strstr($hrs, ',')) {
366                                 $exHrs = explode(',',$hrs);
367                                 foreach($exHrs as $k1 => $hrGroup) {
368                                         if(strstr($hrGroup, '-')) {
369                                                 $exHrGroup = explode('-', $hrGroup);
370                                                 for($i=$exHrGroup[0];$i<=$exHrGroup[1];$i++) {
371                                                         $hrName[] = $i;
372                                                 }
373                                         } else {
374                                                 $hrName[] = $hrGroup;
375                                         }
376                                 }
377                         } elseif(strstr($hrs, '-')) {
378                                 $exHrs = explode('-', $hrs);
379                                 for($i=$exHrs[0];$i<=$exHrs[1];$i++) {
380                                         $hrName[] = $i;
381                                 }
382                         } else {
383                                 $hrName[] = $hrs;
384                         }
385                 }
386                 //_pp($hrName);
387                 // derive minutes
388                 //$currentMin = date('i');
389                 $currentMin = $timedate->getNow()->minute;
390                 if(substr($currentMin, 0, 1) == '0') {
391                         $currentMin = substr($currentMin, 1, 1);
392                 }
393                 if($mins == '*') {
394                         $GLOBALS['log']->debug('----->got * mins');
395                         for($i=0; $i<60; $i++) {
396                                 if(($currentMin + $i) > 59) {
397                                         $minName[] = ($i + $currentMin - 60);
398                                 } else {
399                                         $minName[] = ($i+$currentMin);
400                                 }
401                         }
402                 } elseif(strstr($mins,'*/')) {
403                         $mult = str_replace('*/','',$mins);
404                         $startMin = $timedate->fromDb($focus->date_time_start)->minute;
405                         $startFrom = ($startMin % $mult);
406                         for($i=$startFrom; $i<=59; $i) {
407                                 if(($currentMin + $i) > 59) {
408                                         $minName[] = ($i + $currentMin - 60);
409                                 } else {
410                                         $minName[] = ($i+$currentMin);
411                                 }
412                                 $i += $mult;
413                         }
414
415                 } elseif($mins != '*') {
416                         if(strstr($mins, ',')) {
417                                 $exMins = explode(',',$mins);
418                                 foreach($exMins as $k1 => $minGroup) {
419                                         if(strstr($minGroup, '-')) {
420                                                 $exMinGroup = explode('-', $minGroup);
421                                                 for($i=$exMinGroup[0]; $i<=$exMinGroup[1]; $i++) {
422                                                         $minName[] = $i;
423                                                 }
424                                         } else {
425                                                 $minName[] = $minGroup;
426                                         }
427                                 }
428                         } elseif(strstr($mins, '-')) {
429                                 $exMinGroup = explode('-', $mins);
430                                 for($i=$exMinGroup[0]; $i<=$exMinGroup[1]; $i++) {
431                                         $minName[] = $i;
432                                 }
433                         } else {
434                                 $minName[] = $mins;
435                         }
436                 }
437                 //_pp($minName);
438                 // prep some boundaries - these are not in GMT b/c gmt is a 24hour period, possibly bridging 2 local days
439                 if(empty($focus->time_from)  && empty($focus->time_to) ) {
440                         $timeFromTs = 0;
441                         $timeToTs = $timedate->getNow(true)->get('+1 day')->ts;
442                 } else {
443                     $tfrom = $timedate->fromDbType($focus->time_from, 'time');
444                         $timeFromTs = $timedate->getNow(true)->setTime($tfrom->hour, $tfrom->min)->ts;
445                     $tto = $timedate->fromDbType($focus->time_to, 'time');
446                         $timeToTs = $timedate->getNow(true)->setTime($tto->hour, $tto->min)->ts;
447                 }
448                 $timeToTs++;
449
450                 if(empty($focus->last_run)) {
451                         $lastRunTs = 0;
452                 } else {
453                         $lastRunTs = $timedate->fromDb($focus->last_run)->ts;
454                 }
455
456
457                 /**
458                  * initialize return array
459                  */
460                 $validJobTime = array();
461
462                 global $timedate;
463                 $timeStartTs = $timedate->fromDb($focus->date_time_start)->ts;
464                 if(!empty($focus->date_time_end)) { // do the same for date_time_end if not empty
465                         $timeEndTs = $timedate->fromDb($focus->date_time_end)->ts;
466                 } else {
467                         $timeEndTs = $timedate->getNow(true)->get('+1 day')->ts;
468 //                      $dateTimeEnd = '2020-12-31 23:59:59'; // if empty, set it to something ridiculous
469                 }
470                 $timeEndTs++;
471                 /*_pp('hours:'); _pp($hrName);_pp('mins:'); _pp($minName);*/
472                 $dateobj = $timedate->getNow();
473                 $nowTs = $dateobj->ts;
474         $GLOBALS['log']->debug(sprintf("Constraints: start: %s from: %s end: %s to: %s now: %s",
475             gmdate('Y-m-d H:i:s', $timeStartTs), gmdate('Y-m-d H:i:s', $timeFromTs), gmdate('Y-m-d H:i:s', $timeEndTs),
476             gmdate('Y-m-d H:i:s', $timeToTs), $timedate->nowDb()
477             ));
478 //              _pp('currentHour: '. $currentHour);
479 //              _pp('timeStartTs: '.date('r',$timeStartTs));
480 //              _pp('timeFromTs: '.date('r',$timeFromTs));
481 //              _pp('timeEndTs: '.date('r',$timeEndTs));
482 //              _pp('timeToTs: '.date('r',$timeToTs));
483 //              _pp('mktime: '.date('r',mktime()));
484 //              _pp('timeLastRun: '.date('r',$lastRunTs));
485 //
486 //              _pp('hours: ');
487 //              _pp($hrName);
488 //              _pp('mins: ');
489 //              _ppd($minName);
490                 foreach($hrName as $kHr=>$hr) {
491                         foreach($minName as $kMin=>$min) {
492                             $timedate->tzUser($dateobj);
493                         $dateobj->setTime($hr, $min, 0);
494                         $tsGmt = $dateobj->ts;
495
496                                 if( $tsGmt >= $timeStartTs ) { // start is greater than the date specified by admin
497                                         if( $tsGmt >= $timeFromTs ) { // start is greater than the time_to spec'd by admin
498                         if($tsGmt > $lastRunTs) { // start from last run, last run should not be included
499                             if( $tsGmt <= $timeEndTs ) { // this is taken care of by the initial query - start is less than the date spec'd by admin
500                                 if( $tsGmt <= $timeToTs ) { // start is less than the time_to
501                                     $validJobTime[] = $dateobj->asDb();
502                                 } else {
503                                     //_pp('Job Time is NOT smaller that TimeTO: '.$tsGmt .'<='. $timeToTs);
504                                 }
505                             } else {
506                                 //_pp('Job Time is NOT smaller that DateTimeEnd: '.date('Y-m-d H:i:s',$tsGmt) .'<='. $dateTimeEnd); //_pp( $tsGmt .'<='. $timeEndTs );
507                             }
508                         }
509                                         } else {
510                                                 //_pp('Job Time is NOT bigger that TimeFrom: '.$tsGmt .'>='. $timeFromTs);
511                                         }
512                                 } else {
513                                         //_pp('Job Time is NOT Bigger than DateTimeStart: '.date('Y-m-d H:i',$tsGmt) .'>='. $dateTimeStart);
514                                 }
515                         }
516                 }
517                 //_ppd($validJobTime);
518                 // need ascending order to compare oldest time to last_run
519                 sort($validJobTime);
520                 /**
521                  * If "Execute If Missed bit is set
522                  */
523         $now = TimeDate::getInstance()->getNow();
524                 $now = $now->setTime($now->hour, $now->min, "00")->asDb();
525
526                 if($focus->catch_up == 1) {
527                         if($focus->last_run == null) {
528                                 // always "catch-up"
529                                 $validJobTime[] = $now;
530                         } else {
531                                 // determine what the interval in min/hours is
532                                 // see if last_run is in it
533                                 // if not, add NOW
534                 if(!empty($validJobTime) && ($focus->last_run < $validJobTime[0]) && ($now > $validJobTime[0])) {
535                                 // cn: empty() bug 5914;
536                                 // if(!empty) should be checked, becasue if a scheduler is defined to run every day 4pm, then after 4pm, and it runs as 4pm,
537                                 // the $validJobTime will be empty, and it should not catch up.
538                                 // If $focus->last_run is the the day before yesterday,  it should run yesterday and tomorrow,
539                                 // but it hadn't run yesterday, then it should catch up today.
540                                 // But today is already filtered out when doing date check before. The catch up will not work on this occasion.
541                                 // If the scheduler runs at least one time on each day, I think this bug can be avoided.
542                                         $validJobTime[] = $now;
543                                 }
544                         }
545                 }
546                 return $validJobTime;
547         }
548
549         function handleIntervalType($type, $value, $mins, $hours) {
550                 global $mod_strings;
551                 /* [0]:min [1]:hour [2]:day of month [3]:month [4]:day of week */
552                 $days = array ( 1 => $mod_strings['LBL_MON'],
553                                                 2 => $mod_strings['LBL_TUE'],
554                                                 3 => $mod_strings['LBL_WED'],
555                                                 4 => $mod_strings['LBL_THU'],
556                                                 5 => $mod_strings['LBL_FRI'],
557                                                 6 => $mod_strings['LBL_SAT'],
558                                                 0 => $mod_strings['LBL_SUN'],
559                                                 '*' => $mod_strings['LBL_ALL']);
560                 switch($type) {
561                         case 0: // minutes
562                                 if($value == '0') {
563                                         //return;
564                                         return trim($mod_strings['LBL_ON_THE']).$mod_strings['LBL_HOUR_SING'];
565                                 } elseif(!preg_match('/[^0-9]/', $hours) && !preg_match('/[^0-9]/', $value)) {
566                                         return;
567
568                                 } elseif(preg_match('/\*\//', $value)) {
569                                         $value = str_replace('*/','',$value);
570                                         return $value.$mod_strings['LBL_MINUTES'];
571                                 } elseif(!preg_match('[^0-9]', $value)) {
572                                         return $mod_strings['LBL_ON_THE'].$value.$mod_strings['LBL_MIN_MARK'];
573                                 } else {
574                                         return $value;
575                                 }
576                         case 1: // hours
577                                 global $current_user;
578                                 if(preg_match('/\*\//', $value)) { // every [SOME INTERVAL] hours
579                                         $value = str_replace('*/','',$value);
580                                         return $value.$mod_strings['LBL_HOUR'];
581                                 } elseif(preg_match('/[^0-9]/', $mins)) { // got a range, or multiple of mins, so we return an 'Hours' label
582                                         return $value;
583                                 } else {        // got a "minutes" setting, so it will be at some o'clock.
584                                         $datef = $current_user->getUserDateTimePreferences();
585                                         return date($datef['time'], strtotime($value.':'.str_pad($mins, 2, '0', STR_PAD_LEFT)));
586                                 }
587                         case 2: // day of month
588                                 if(preg_match('/\*/', $value)) {
589                                         return $value;
590                                 } else {
591                                         return date('jS', strtotime('December '.$value));
592                                 }
593
594                         case 3: // months
595                                 return date('F', strtotime('2005-'.$value.'-01'));
596                         case 4: // days of week
597                                 return $days[$value];
598                         default:
599                                 return 'bad'; // no condition to touch this branch
600                 }
601         }
602
603         function setIntervalHumanReadable() {
604                 global $current_user;
605                 global $mod_strings;
606
607                 /* [0]:min [1]:hour [2]:day of month [3]:month [4]:day of week */
608                 $ints = $this->intervalParsed;
609                 $intVal = array('-', ',');
610                 $intSub = array($mod_strings['LBL_RANGE'], $mod_strings['LBL_AND']);
611                 $intInt = array(0 => $mod_strings['LBL_MINS'], 1 => $mod_strings['LBL_HOUR']);
612                 $tempInt = '';
613                 $iteration = '';
614
615                 foreach($ints['raw'] as $key => $interval) {
616                         if($tempInt != $iteration) {
617                                 $tempInt .= '; ';
618                         }
619                         $iteration = $tempInt;
620
621                         if($interval != '*' && $interval != '*/1') {
622                                 if(false !== strpos($interval, ',')) {
623                                         $exIndiv = explode(',', $interval);
624                                         foreach($exIndiv as $val) {
625                                                 if(false !== strpos($val, '-')) {
626                                                         $exRange = explode('-', $val);
627                                                         foreach($exRange as $valRange) {
628                                                                 if($tempInt != '') {
629                                                                         $tempInt .= $mod_strings['LBL_AND'];
630                                                                 }
631                                                                 $tempInt .= $this->handleIntervalType($key, $valRange, $ints['raw'][0], $ints['raw'][1]);
632                                                         }
633                                                 } elseif($tempInt != $iteration) {
634                                                         $tempInt .= $mod_strings['LBL_AND'];
635                                                 }
636                                                 $tempInt .= $this->handleIntervalType($key, $val, $ints['raw'][0], $ints['raw'][1]);
637                                         }
638                                 } elseif(false !== strpos($interval, '-')) {
639                                         $exRange = explode('-', $interval);
640                                         $tempInt .= $mod_strings['LBL_FROM'];
641                                         $check = $tempInt;
642
643                                         foreach($exRange as $val) {
644                                                 if($tempInt == $check) {
645                                                         $tempInt .= $this->handleIntervalType($key, $val, $ints['raw'][0], $ints['raw'][1]);
646                                                         $tempInt .= $mod_strings['LBL_RANGE'];
647
648                                                 } else {
649                                                         $tempInt .= $this->handleIntervalType($key, $val, $ints['raw'][0], $ints['raw'][1]);
650                                                 }
651                                         }
652
653                                 } elseif(false !== strpos($interval, '*/')) {
654                                         $tempInt .= $mod_strings['LBL_EVERY'];
655                                         $tempInt .= $this->handleIntervalType($key, $interval, $ints['raw'][0], $ints['raw'][1]);
656                                 } else {
657                                         $tempInt .= $this->handleIntervalType($key, $interval, $ints['raw'][0], $ints['raw'][1]);
658                                 }
659                         }
660                 } // end foreach()
661
662                 if($tempInt == '') {
663                         $this->intervalHumanReadable = $mod_strings['LBL_OFTEN'];
664                 } else {
665                         $tempInt = trim($tempInt);
666                         if(';' == substr($tempInt, (strlen($tempInt)-1), strlen($tempInt))) {
667                                 $tempInt = substr($tempInt, 0, (strlen($tempInt)-1));
668                         }
669                         $this->intervalHumanReadable = $tempInt;
670                 }
671         }
672
673
674         /* take an integer and return its suffix */
675         function setStandardArraysAttributes() {
676                 global $mod_strings;
677                 global $app_list_strings; // using from month _dom list
678
679                 $suffArr = array('','st','nd','rd');
680                 for($i=1; $i<32; $i++) {
681                         if($i > 3 && $i < 21) {
682                                 $this->suffixArray[$i] = $i."th";
683                         } elseif (substr($i,-1,1) < 4 && substr($i,-1,1) > 0) {
684                                 $this->suffixArray[$i] = $i.$suffArr[substr($i,-1,1)];
685                         } else {
686                                 $this->suffixArray[$i] = $i."th";
687                         }
688                         $this->datesArray[$i] = $i;
689                 }
690
691                 $this->dayInt = array('*',1,2,3,4,5,6,0);
692                 $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']);
693                 $this->monthsInt = array(0,1,2,3,4,5,6,7,8,9,10,11,12);
694                 $this->monthsLabel = $app_list_strings['dom_cal_month_long'];
695                 $this->metricsVar = array("*", "/", "-", ",");
696                 $this->metricsVal = array(' every ','',' thru ',' and ');
697         }
698
699         /**
700          *  takes the serialized interval string and renders it into an array
701          */
702         function parseInterval() {
703                 global $metricsVar;
704                 $ws = array(' ', '\r','\t');
705                 $blanks = array('','','');
706
707                 $intv = $this->job_interval;
708                 $rawValues = explode('::', $intv);
709                 $rawProcessed = str_replace($ws,$blanks,$rawValues); // strip all whitespace
710
711                 $hours = $rawValues[1].':::'.$rawValues[0];
712                 $months = $rawValues[3].':::'.$rawValues[2];
713
714                 $intA = array ( 'raw' => $rawProcessed,
715                                                 'hours' => $hours,
716                                                 'months' => $months,
717                                                 );
718
719                 $this->intervalParsed = $intA;
720         }
721
722         /**
723          * checks for cURL libraries
724          */
725         function checkCurl() {
726                 global $mod_strings;
727
728                 if(!function_exists('curl_init')) {
729                         echo '
730                         <table cellpadding="0" cellspacing="0" width="100%" border="0" class="list view">
731                                 <tr height="20">
732                                         <th width="25%" colspan="2"><slot>
733                                                 '.$mod_strings['LBL_WARN_CURL_TITLE'].'
734                                         </slot></td>
735                                 </tr>
736                                 <tr class="oddListRowS1" >
737                                         <td scope="row" valign=TOP width="20%"><slot>
738                                                 '.$mod_strings['LBL_WARN_CURL'].'
739                                         <td scope="row" valign=TOP width="80%"><slot>
740                                                 <span class=error>'.$mod_strings['LBL_WARN_NO_CURL'].'</span>
741                                         </slot></td>
742                                 </tr>
743                         </table>
744                         <br>';
745                 }
746         }
747
748         function displayCronInstructions() {
749                 global $mod_strings;
750                 global $sugar_config;
751                 $error = '';
752                 if (!isset($_SERVER['Path'])) {
753             $_SERVER['Path'] = getenv('Path');
754         }
755         if(is_windows()) {
756                         if(isset($_SERVER['Path']) && !empty($_SERVER['Path'])) { // IIS IUSR_xxx may not have access to Path or it is not set
757                                 if(!strpos($_SERVER['Path'], 'php')) {
758 //                                      $error = '<em>'.$mod_strings['LBL_NO_PHP_CLI'].'</em>';
759                                 }
760                         }
761                 } else {
762                         if(isset($_SERVER['Path']) && !empty($_SERVER['Path'])) { // some Linux servers do not make this available
763                                 if(!strpos($_SERVER['PATH'], 'php')) {
764 //                                      $error = '<em>'.$mod_strings['LBL_NO_PHP_CLI'].'</em>';
765                                 }
766                         }
767                 }
768
769
770
771                 if(is_windows()) {
772                         echo '<br>';
773                         echo '
774                                 <table cellpadding="0" cellspacing="0" width="100%" border="0" class="list view">
775                                 <tr height="20">
776                                         <th><slot>
777                                                 '.$mod_strings['LBL_CRON_INSTRUCTIONS_WINDOWS'].'
778                                         </slot></th>
779                                 </tr>
780                                 <tr class="evenListRowS1">
781                                         <td scope="row" valign="top" width="70%"><slot>
782                                                 '.$mod_strings['LBL_CRON_WINDOWS_DESC'].'<br>
783                                                 <b>cd '.realpath('./').'<br>
784                                                 php.exe -f cron.php</b>
785                                         </slot></td>
786                                 </tr>
787                         </table>';
788                 } else {
789                         echo '<br>';
790                         echo '
791                                 <table cellpadding="0" cellspacing="0" width="100%" border="0" class="list view">
792                                 <tr height="20">
793                                         <th><slot>
794                                                 '.$mod_strings['LBL_CRON_INSTRUCTIONS_LINUX'].'
795                                         </slot></th>
796                                 </tr>
797                                 <tr>
798                                         <td scope="row" valign=TOP class="oddListRowS1" bgcolor="#fdfdfd" width="70%"><slot>
799                                                 '.$mod_strings['LBL_CRON_LINUX_DESC'].'<br>
800                                                 <b>*&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;
801                                                 cd '.realpath('./').'; php -f cron.php > /dev/null 2>&1</b>
802                                                 <br>'.$error.'
803                                         </slot></td>
804                                 </tr>
805                         </table>';
806                 }
807         }
808
809         /**
810          * Archives schedulers of the same functionality, then instantiates new
811          * ones.
812          */
813         function rebuildDefaultSchedulers() {
814                 $mod_strings = return_module_language($GLOBALS['current_language'], 'Schedulers');
815                 // truncate scheduler-related tables
816                 $this->db->query('DELETE FROM schedulers');
817
818
819         $sched3 = new Scheduler();
820         $sched3->name               = $mod_strings['LBL_OOTB_TRACKER'];
821         $sched3->job                = 'function::trimTracker';
822         $sched3->date_time_start    = create_date(2005,1,1) . ' ' . create_time(0,0,1);
823         $sched3->date_time_end      = create_date(2020,12,31) . ' ' . create_time(23,59,59);
824         $sched3->job_interval       = '0::2::1::*::*';
825         $sched3->status             = 'Active';
826         $sched3->created_by         = '1';
827         $sched3->modified_user_id   = '1';
828         $sched3->catch_up           = '1';
829         $sched3->save();
830                 $sched4 = new Scheduler();
831                 $sched4->name                           = $mod_strings['LBL_OOTB_IE'];
832                 $sched4->job                            = 'function::pollMonitoredInboxes';
833                 $sched4->date_time_start        = create_date(2005,1,1) . ' ' . create_time(0,0,1);
834                 $sched4->date_time_end          = create_date(2020,12,31) . ' ' . create_time(23,59,59);
835                 $sched4->job_interval           = '*::*::*::*::*';
836                 $sched4->status                         = 'Active';
837                 $sched4->created_by                     = '1';
838                 $sched4->modified_user_id       = '1';
839                 $sched4->catch_up                       = '0';
840                 $sched4->save();
841
842                 $sched5 = new Scheduler();
843                 $sched5->name                           = $mod_strings['LBL_OOTB_BOUNCE'];
844                 $sched5->job                            = 'function::pollMonitoredInboxesForBouncedCampaignEmails';
845                 $sched5->date_time_start        = create_date(2005,1,1) . ' ' . create_time(0,0,1);
846                 $sched5->date_time_end          = create_date(2020,12,31) . ' ' . create_time(23,59,59);
847                 $sched5->job_interval           = '0::2-6::*::*::*';
848                 $sched5->status                         = 'Active';
849                 $sched5->created_by                     = '1';
850                 $sched5->modified_user_id       = '1';
851                 $sched5->catch_up                       = '1';
852                 $sched5->save();
853
854                 $sched6 = new Scheduler();
855                 $sched6->name                           = $mod_strings['LBL_OOTB_CAMPAIGN'];
856                 $sched6->job                            = 'function::runMassEmailCampaign';
857                 $sched6->date_time_start        = create_date(2005,1,1) . ' ' . create_time(0,0,1);
858                 $sched6->date_time_end          = create_date(2020,12,31) . ' ' . create_time(23,59,59);
859                 $sched6->job_interval           = '0::2-6::*::*::*';
860                 $sched6->status                         = 'Active';
861                 $sched6->created_by                     = '1';
862                 $sched6->modified_user_id       = '1';
863                 $sched6->catch_up                       = '1';
864                 $sched6->save();
865
866
867         $sched7 = new Scheduler();
868         $sched7->name               = $mod_strings['LBL_OOTB_PRUNE'];
869         $sched7->job                = 'function::pruneDatabase';
870         $sched7->date_time_start    = create_date(2005,1,1) . ' ' . create_time(0,0,1);
871         $sched7->date_time_end      = create_date(2020,12,31) . ' ' . create_time(23,59,59);
872         $sched7->job_interval       = '0::4::1::*::*';
873         $sched7->status             = 'Inactive';
874         $sched7->created_by         = '1';
875         $sched7->modified_user_id   = '1';
876         $sched7->catch_up           = '0';
877         $sched7->save();
878
879
880
881
882         $sched12 = new Scheduler();
883         $sched12->name               = $mod_strings['LBL_OOTB_SEND_EMAIL_REMINDERS'];
884         $sched12->job                = 'function::sendEmailReminders';
885         $sched12->date_time_start    = create_date(2008,1,1) . ' ' . create_time(0,0,1);
886         $sched12->date_time_end      = create_date(2020,12,31) . ' ' . create_time(23,59,59);
887         $sched12->job_interval       = '*::*::*::*::*';
888         $sched12->status             = 'Active';
889         $sched12->created_by         = '1';
890         $sched12->modified_user_id   = '1';
891         $sched12->catch_up           = '0';
892         $sched12->save();
893
894         $sched13 = new Scheduler();
895         $sched13->name               = $mod_strings['LBL_OOTB_CLEANUP_QUEUE'];
896         $sched13->job                = 'function::cleanJobQueue';
897         $sched13->date_time_start    = create_date(2012,1,1) . ' ' . create_time(0,0,1);
898         $sched13->date_time_end      = create_date(2030,12,31) . ' ' . create_time(23,59,59);
899         $sched13->job_interval       = '0::5::*::*::*';
900         $sched13->status             = 'Active';
901         $sched13->created_by         = '1';
902         $sched13->modified_user_id   = '1';
903         $sched13->catch_up           = '0';
904         $sched13->save();
905         }
906
907         ////    END SCHEDULER HELPER FUNCTIONS
908         ///////////////////////////////////////////////////////////////////////////
909
910
911         ///////////////////////////////////////////////////////////////////////////
912         ////    STANDARD SUGARBEAN OVERRIDES
913         /**
914          * function overrides the one in SugarBean.php
915          */
916         function create_export_query($order_by, $where, $show_deleted = 0) {
917                 return $this->create_new_list_query($order_by, $where,array(),array(), $show_deleted = 0);
918         }
919
920         /**
921          * function overrides the one in SugarBean.php
922          */
923
924         /**
925          * function overrides the one in SugarBean.php
926          */
927         function fill_in_additional_list_fields() {
928                 $this->fill_in_additional_detail_fields();
929         }
930
931         /**
932          * function overrides the one in SugarBean.php
933          */
934         function fill_in_additional_detail_fields() {
935     }
936
937         /**
938          * function overrides the one in SugarBean.php
939          */
940         function get_list_view_data()
941         {
942                 global $mod_strings;
943                 $temp_array = $this->get_list_view_array();
944         $temp_array["ENCODED_NAME"]=$this->name;
945         $this->parseInterval();
946         $this->setIntervalHumanReadable();
947         $temp_array['JOB_INTERVAL'] = $this->intervalHumanReadable;
948         if($this->date_time_end == '2020-12-31 23:59' || $this->date_time_end == '') {
949                 $temp_array['DATE_TIME_END'] = $mod_strings['LBL_PERENNIAL'];
950         }
951         $this->created_by_name = get_assigned_user_name($this->created_by);
952                 $this->modified_by_name = get_assigned_user_name($this->modified_user_id);
953         return $temp_array;
954
955         }
956
957         /**
958          * returns the bean name - overrides SugarBean's
959          */
960         function get_summary_text()
961         {
962                 return $this->name;
963         }
964         ////    END STANDARD SUGARBEAN OVERRIDES
965         ///////////////////////////////////////////////////////////////////////////
966         static public function getJobsList()
967         {
968                 if(empty(self::$job_strings)) {
969                         global $mod_strings;
970                         include_once('modules/Schedulers/_AddJobsHere.php');
971
972                         // job functions
973                         self::$job_strings = array('url::' => 'URL');
974                         foreach($job_strings as $k=>$v){
975                                 self::$job_strings['function::' . $v] = $mod_strings['LBL_'.strtoupper($v)];
976                         }
977                 }
978                 return self::$job_strings;
979         }
980 } // end class definition