PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/concrete/core/models/job.php

https://bitbucket.org/selfeky/xclusivescardwebsite
PHP | 439 lines | 321 code | 64 blank | 54 comment | 41 complexity | 32f2fbe0bdf1722618d0e54e83e4992b MD5 | raw file
  1. <?php
  2. defined('C5_EXECUTE') or die("Access Denied.");
  3. /**
  4. *
  5. * Contains the job class.
  6. * @package Utilities
  7. * @author Andrew Embler <andrew@concrete5.org>
  8. * @author Tony Trupp <tony@concrete5.org>
  9. * @link http://www.concrete5.org
  10. * @license http://www.opensource.org/licenses/mit-license.php MIT
  11. *
  12. */
  13. /**
  14. *
  15. * The job class is essentially sub-dispatcher for certain maintenance tasks that need to be run at specified intervals. Examples include indexing a search engine or generating a sitemap page.
  16. * @package Utilities
  17. * @author Andrew Embler <andrew@concrete5.org>
  18. * @author Tony Trupp <tony@concrete5.org>
  19. * @link http://www.concrete5.org
  20. * @license http://www.opensource.org/licenses/mit-license.php MIT
  21. *
  22. */
  23. abstract class Concrete5_Model_Job extends Object {
  24. const JOB_SUCCESS = 0;
  25. const JOB_ERROR_EXCEPTION_GENERAL = 1;
  26. abstract public function run();
  27. abstract public function getJobName();
  28. abstract public function getJobDescription();
  29. public function getJobHandle() {return $this->jHandle;}
  30. public function getJobID() {return $this->jID;}
  31. public function getPackageHandle() {
  32. return PackageList::getHandle($this->pkgID);
  33. }
  34. public function getJobLastStatusCode() {
  35. return $this->jLastStatusCode;
  36. }
  37. public function didFail() {
  38. return in_array($this->jLastStatusCode, array(
  39. self::JOB_ERROR_EXCEPTION_GENERAL
  40. ));
  41. }
  42. public function canUninstall() {
  43. return $this->jNotUninstallable != 1;
  44. }
  45. public function supportsQueue() {return ($this instanceof QueueableJob);}
  46. //==========================================================
  47. // JOB MANAGEMENT - do not override anything below this line
  48. //==========================================================
  49. //meta variables
  50. protected $jobClassLocations=array();
  51. //Other Job Variables
  52. public $jID=0;
  53. public $jStatus='ENABLED';
  54. public $availableJStatus=array( 'ENABLED','RUNNING','DISABLED_ERROR','DISABLED' );
  55. public $jDateLastRun;
  56. public $jHandle='';
  57. public $jNotUninstallable=0;
  58. public $isScheduled = 0;
  59. public $scheduledInterval = 'days'; // hours|days|weeks|months
  60. public $scheduledValue = 0;
  61. /*
  62. final public __construct(){
  63. //$this->jHandle="example_job_file.php";
  64. }
  65. */
  66. public static function jobClassLocations(){
  67. return array(DIR_FILES_JOBS, DIR_FILES_JOBS_CORE);
  68. }
  69. public function getJobDateLastRun() {return $this->jDateLastRun;}
  70. public function getJobStatus() {return $this->jStatus;}
  71. public function getJobLastStatusText() {return $this->jLastStatusText;}
  72. // authenticateRequest checks against your site's salt and a custom auth field to make
  73. // sure that this is a request that is coming either from something cronned by the site owner
  74. // or from the dashboard
  75. public static function authenticateRequest($auth) {
  76. $val = PASSWORD_SALT . ':' . DIRNAME_JOBS;
  77. return md5($val) == $auth;
  78. }
  79. public static function generateAuth() {
  80. $val = PASSWORD_SALT . ':' . DIRNAME_JOBS;
  81. return md5($val);
  82. }
  83. public static function exportList($xml) {
  84. $jobs = Job::getList();
  85. if (!$jobs) {
  86. return;
  87. }
  88. $jx = $xml->addChild('jobs');
  89. foreach($jobs as $job) {
  90. $ch = $jx->addChild('job');
  91. $ch->addAttribute('handle',$job->getJobHandle());
  92. $ch->addAttribute('package',$job->getPackageHandle());
  93. }
  94. }
  95. // Job Retrieval
  96. // ==============
  97. public static function getList($scheduledOnly = false){
  98. $db = Loader::db();
  99. if($scheduledOnly) {
  100. $q = "SELECT jID FROM Jobs WHERE isScheduled = 1 ORDER BY jDateLastRun";
  101. } else {
  102. $q = "SELECT jID FROM Jobs ORDER BY jDateLastRun";
  103. }
  104. $r = $db->Execute($q);
  105. $jobs = array();
  106. while ($row = $r->FetchRow()) {
  107. $j = Job::getByID($row['jID']);
  108. if (is_object($j)) {
  109. $jobs[] = $j;
  110. }
  111. }
  112. return $jobs;
  113. }
  114. public function reset() {
  115. $db = Loader::db();
  116. $db->Execute('update Jobs set jLastStatusCode = 0, jStatus = \'ENABLED\' where jID = ?', array($this->jID));
  117. }
  118. public function markStarted(){
  119. Events::fire('on_before_job_execute', $this);
  120. $db = Loader::db();
  121. $timestampH =date('Y-m-d g:i:s A');
  122. $timestamp=date('Y-m-d H:i:s');
  123. $this->jDateLastRun = $timestampH;
  124. $rs = $db->query( "UPDATE Jobs SET jStatus='RUNNING', jDateLastRun=? WHERE jHandle=?", array( $timestamp, $this->jHandle ) );
  125. }
  126. public function markCompleted($resultCode = 0, $resultMsg = false) {
  127. $db = Loader::db();
  128. if (!$resultMsg) {
  129. $resultMsg= t('The Job was run successfully.');
  130. }
  131. if (!$resultCode) {
  132. $resultCode = 0;
  133. }
  134. $jStatus='ENABLED';
  135. if ($this->didFail()) {
  136. $jStatus = 'ERROR';
  137. }
  138. $timestamp=date('Y-m-d H:i:s');
  139. $rs = $db->query( "UPDATE Jobs SET jStatus=?, jLastStatusCode = ?, jLastStatusText=? WHERE jHandle=?", array( $jStatus, $resultCode, $resultMsg, $this->jHandle ) );
  140. $rs = $db->query( "INSERT INTO JobsLog (jID, jlMessage, jlTimestamp, jlError) VALUES(?,?,?,?)", array( $this->jID, $resultMsg, $timestamp, $resultCode ) );
  141. Events::fire('on_job_execute', $this);
  142. $obj = new stdClass;
  143. $obj->error = $resultCode;
  144. $obj->result = $resultMsg;
  145. $obj->jDateLastRun = date(DATE_APP_GENERIC_MDYT_FULL_SECONDS);
  146. $this->jLastStatusCode = $resultCode;
  147. $this->jLastStatusText = $resultMsg;
  148. $this->jStatus = $jStatus;
  149. return $obj;
  150. }
  151. public static function getByID( $jID=0 ){
  152. $db = Loader::db();
  153. $jobData = $db->getRow("SELECT * FROM Jobs WHERE jID=".intval($jID));
  154. if( !$jobData || !$jobData['jHandle'] ) return NULL;
  155. return Job::getJobObjByHandle( $jobData['jHandle'], $jobData );
  156. }
  157. public static function getByHandle( $jHandle='' ){
  158. $db = Loader::db();
  159. $jobData = $db->getRow( 'SELECT * FROM Jobs WHERE jHandle=?', array($jHandle) );
  160. if( !$jobData || !$jobData['jHandle'] ) return NULL;
  161. return Job::getJobObjByHandle( $jobData['jHandle'], $jobData );
  162. }
  163. public static function getJobObjByHandle( $jHandle='', $jobData=array() ){
  164. $jcl = Job::jobClassLocations();
  165. //check for the job file in the various locations
  166. $db = Loader::db();
  167. $pkgID = $db->GetOne('select pkgID from Jobs where jHandle = ?', $jHandle);
  168. if ($pkgID > 0) {
  169. $pkgHandle = PackageList::getHandle($pkgID);
  170. if ($pkgHandle) {
  171. $jcl[] = DIR_PACKAGES . '/' . $pkgHandle . '/' . DIRNAME_JOBS;
  172. $jcl[] = DIR_PACKAGES_CORE . '/' . $pkgHandle . '/' . DIRNAME_JOBS;
  173. }
  174. }
  175. foreach( $jcl as $jobClassLocation ){
  176. //load the file & class, then run the job
  177. $path=$jobClassLocation.'/'.$jHandle.'.php';
  178. if( file_exists($path) ){
  179. require_once($path);
  180. $className=Object::camelcase( $jHandle );
  181. $j = new $className();
  182. $j->jHandle=$jHandle;
  183. if(intval($jobData['jID'])>0){
  184. $j->setPropertiesFromArray($jobData);
  185. }
  186. return $j;
  187. }
  188. }
  189. return NULL;
  190. }
  191. //Scan job directories for job classes
  192. public static function getAvailableList($includeConcreteDirJobs=1){
  193. $jobObjs=array();
  194. //get existing jobs
  195. $existingJobHandles=array();
  196. $existingJobs = Job::getList();
  197. foreach($existingJobs as $j) {
  198. $existingJobHandles[] = $j->getJobHandle();
  199. }
  200. if(!$includeConcreteDirJobs)
  201. $jobClassLocations = array( DIR_FILES_JOBS );
  202. else $jobClassLocations = Job::jobClassLocations();
  203. foreach( $jobClassLocations as $jobClassLocation){
  204. // Open a known directory, and proceed to read its contents
  205. if (is_dir($jobClassLocation)) {
  206. if ($dh = opendir($jobClassLocation)) {
  207. while (($file = readdir($dh)) !== false) {
  208. if( substr($file,strlen($file)-4)!='.php' ) continue;
  209. $alreadyInstalled=0;
  210. foreach($existingJobHandles as $existingJobHandle){
  211. if( substr($file,0,strlen($file)-4)==$existingJobHandle){
  212. $alreadyInstalled=1;
  213. break;
  214. }
  215. }
  216. if($alreadyInstalled) continue;
  217. $path=$jobClassLocation .'/'. $file;
  218. require_once( $jobClassLocation .'/'. $file );
  219. $jHandle = substr($file,0,strlen($file)-4);
  220. $className=Object::camelcase( $jHandle );
  221. if(class_exists($className)){
  222. $jobObjs[$jHandle]=new $className();
  223. $jobObjs[$jHandle]->jHandle=$jHandle;
  224. if(!$jobObjs[$jHandle] instanceof Job){
  225. $jobObjs[$jHandle]->jDescription= t('Error: The Job class must be a child class of Job.');
  226. $jobObjs[$jHandle]->invalid=1;
  227. }
  228. }else{
  229. $invalidJob = new Job();
  230. $invalidJob->jName = $className;
  231. $invalidJob->jHandle=$jHandle;
  232. $invalidJob->jDescription = t('Error: Invalid Job file. The class %s was not found in %s .', $className, $path);
  233. $invalidJob->invalid=1;
  234. $jobObjs[$jHandle] = $invalidJob;
  235. }
  236. }
  237. closedir($dh);
  238. }
  239. }
  240. }
  241. return $jobObjs;
  242. }
  243. // Running Jobs
  244. // ==============
  245. /*
  246. public static function runAllJobs(){
  247. //loop through all installed jobs
  248. $jobs = Job::getList();
  249. foreach($jobs as $j) {
  250. $j->executeJob();
  251. }
  252. }
  253. */
  254. public function executeJob() {
  255. $this->markStarted();
  256. try{
  257. $resultMsg=$this->run();
  258. if(strlen($resultMsg)==0) {
  259. $resultMsg= t('The Job was run successfully.');
  260. }
  261. }catch(Exception $e){
  262. $resultMsg=$e->getMessage();
  263. $error = self::JOB_ERROR_EXCEPTION_GENERAL;
  264. }
  265. Events::fire('on_job_execute', $this);
  266. $obj = $this->markCompleted($error, $resultMsg);
  267. return $obj;
  268. }
  269. public function setJobStatus($jStatus='ENABLED'){
  270. $db = Loader::db();
  271. if( !in_array($jStatus,$this->availableJStatus) )
  272. $jStatus='ENABLED';
  273. $rs = $db->query( "UPDATE Jobs SET jStatus=? WHERE jHandle=?", array( $jStatus, $this->jHandle ) );
  274. }
  275. public function installByHandle($jHandle=''){
  276. $availableJobs=Job::getAvailableList();
  277. foreach( $availableJobs as $availableJobHandle=>$availableJobObj ){
  278. if( $availableJobObj->jHandle!=$jHandle ) continue;
  279. $availableJobObj->install();
  280. }
  281. }
  282. public static function getListByPackage($pkg) {
  283. $db = Loader::db();
  284. $list = array();
  285. $r = $db->Execute('select jHandle from Jobs where pkgID = ? order by jHandle asc', array($pkg->getPackageID()));
  286. while ($row = $r->FetchRow()) {
  287. $list[] = Job::getJobObjByHandle($row['jHandle']);
  288. }
  289. $r->Close();
  290. return $list;
  291. }
  292. public function installByPackage($jHandle, $pkg) {
  293. $dir = is_dir(DIR_PACKAGES . '/' . $pkg->getPackageHandle()) ? DIR_PACKAGES . '/' . $pkg->getPackageHandle() : DIR_PACKAGES_CORE . '/' . $pkg->getPackageHandle();
  294. require_once( $dir .'/'. DIRNAME_JOBS . '/' . $jHandle . '.php');
  295. $className=Object::camelcase( $jHandle );
  296. if(class_exists($className)){
  297. $j = new $className();
  298. $db = Loader::db();
  299. $db->Execute('insert into Jobs (jName, jDescription, jDateInstalled, jNotUninstallable, jHandle, pkgID) values (?, ?, ?, ?, ?, ?)',
  300. array($j->getJobName(), $j->getJobDescription(), Loader::helper('date')->getLocalDateTime(), 0, $jHandle, $pkg->getPackageID()));
  301. Events::fire('on_job_install', $j);
  302. return $j;
  303. }
  304. }
  305. public function install(){
  306. $db = Loader::db();
  307. $jobExists=$db->getOne( 'SELECT count(*) FROM Jobs WHERE jHandle=?', array($this->jHandle) );
  308. $vals=array($this->getJobName(),$this->getJobDescription(), date('Y-m-d H:i:s'), $this->jNotUninstallable, $this->jHandle);
  309. if($jobExists){
  310. $db->query('UPDATE Jobs SET jName=?, jDescription=?, jDateInstalled=?, jNotUninstallable=? WHERE jHandle=?',$vals);
  311. }else{
  312. $db->query('INSERT INTO Jobs (jName, jDescription, jDateInstalled, jNotUninstallable, jHandle) VALUES(?,?,?,?,?)',$vals);
  313. }
  314. Events::fire('on_job_install', $this);
  315. }
  316. public function uninstall(){
  317. $ret = Events::fire('on_job_uninstall', $this);
  318. if($ret < 0) {
  319. return $ret;
  320. }
  321. $db = Loader::db();
  322. $db->query( 'DELETE FROM Jobs WHERE jHandle=?', array($this->jHandle) );
  323. }
  324. /**
  325. * Removes Job log entries
  326. */
  327. public static function clearLog() {
  328. $db = Loader::db();
  329. $db->Execute("delete from JobsLog");
  330. }
  331. public function isScheduledForNow() {
  332. if(!$this->isScheduled) {
  333. return false;
  334. }
  335. if($this->scheduledValue <= 0) {
  336. return false;
  337. }
  338. $last_run = strtotime($this->jDateLastRun);
  339. $seconds = 1;
  340. switch($this->scheduledInterval) {
  341. case "hours":
  342. $seconds = 60*60;
  343. break;
  344. case "days":
  345. $seconds = 60*60*24;
  346. break;
  347. case "weeks":
  348. $seconds = 60*60*24*7;
  349. break;
  350. case "months":
  351. $seconds = 60*60*24*7*30;
  352. break;
  353. }
  354. $gap = $this->scheduledValue * $seconds;
  355. if($last_run < (time() - $gap) ) {
  356. return true;
  357. } else {
  358. return false;
  359. }
  360. }
  361. public function setSchedule($scheduled, $interval, $value) {
  362. $this->isScheduled = ($scheduled?true:false);
  363. $this->scheduledInterval = $interval;
  364. $this->scheduledValue = $value;
  365. if($this->getJobID()) {
  366. $db = Loader::db();
  367. $db->query("UPDATE Jobs SET isScheduled = ?, scheduledInterval = ?, scheduledValue = ? WHERE jID = ?",
  368. array($this->isScheduled, $this->scheduledInterval, $this->scheduledValue, $this->getJobID()));
  369. return true;
  370. } else {
  371. return false;
  372. }
  373. }
  374. }
  375. ?>