Add an 'Execute Now' button to the job log
[civicrm-core.git] / CRM / Admin / Form / Job.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * Class for configuring jobs.
20 */
21 class CRM_Admin_Form_Job extends CRM_Admin_Form {
22 public $_id = NULL;
23
24 public function preProcess() {
25
26 parent::preProcess();
27 $this->setContext();
28
29 CRM_Utils_System::setTitle(ts('Manage - Scheduled Jobs'));
30
31 if ($this->_id) {
32 $refreshURL = CRM_Utils_System::url('civicrm/admin/job',
33 "reset=1&action=update&id={$this->_id}",
34 FALSE, NULL, FALSE
35 );
36 }
37 else {
38 $refreshURL = CRM_Utils_System::url('civicrm/admin/job',
39 "reset=1&action=add",
40 FALSE, NULL, FALSE
41 );
42 }
43
44 $this->assign('refreshURL', $refreshURL);
45 }
46
47 /**
48 * Build the form object.
49 *
50 * @param bool $check
51 */
52 public function buildQuickForm($check = FALSE) {
53 parent::buildQuickForm();
54
55 if ($this->_action & CRM_Core_Action::DELETE) {
56 return;
57 }
58
59 if ($this->_action & CRM_Core_Action::VIEW) {
60 $this->assign('jobName', self::getJobName($this->_id));
61 $this->addButtons([
62 [
63 'type' => 'submit',
64 'name' => ts('Execute'),
65 'isDefault' => TRUE,
66 ],
67 [
68 'type' => 'cancel',
69 'name' => ts('Cancel'),
70 ],
71 ]);
72 return;
73 }
74
75 $attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_Job');
76
77 $this->add('text', 'name', ts('Name'),
78 $attributes['name'], TRUE
79 );
80
81 $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', [
82 'CRM_Core_DAO_Job',
83 $this->_id,
84 ]);
85
86 $this->add('text', 'description', ts('Description'),
87 $attributes['description']
88 );
89
90 $this->add('text', 'api_entity', ts('API Call Entity'),
91 $attributes['api_entity'], TRUE
92 );
93
94 $this->add('text', 'api_action', ts('API Call Action'),
95 $attributes['api_action'], TRUE
96 );
97
98 $this->add('select', 'run_frequency', ts('Run frequency'), CRM_Core_SelectValues::getJobFrequency());
99
100 // CRM-17686
101 $this->add('datepicker', 'scheduled_run_date', ts('Scheduled Run Date'), NULL, FALSE, ['minDate' => date('Y-m-d')]);
102
103 $this->add('textarea', 'parameters', ts('Command parameters'),
104 "cols=50 rows=6"
105 );
106
107 // is this job active ?
108 $this->add('checkbox', 'is_active', ts('Is this Scheduled Job active?'));
109
110 $this->addFormRule(['CRM_Admin_Form_Job', 'formRule']);
111 }
112
113 /**
114 * @param $fields
115 *
116 * @return array|bool
117 * @throws API_Exception
118 */
119 public static function formRule($fields) {
120
121 $errors = [];
122
123 require_once 'api/api.php';
124
125 /** @var \Civi\API\Kernel $apiKernel */
126 $apiKernel = \Civi::service('civi_api_kernel');
127 $apiRequest = \Civi\API\Request::create($fields['api_entity'], $fields['api_action'], ['version' => 3]);
128 try {
129 $apiKernel->resolve($apiRequest);
130 }
131 catch (\Civi\API\Exception\NotImplementedException $e) {
132 $errors['api_action'] = ts('Given API command is not defined.');
133 }
134
135 if (!empty($errors)) {
136 return $errors;
137 }
138
139 return empty($errors) ? TRUE : $errors;
140 }
141
142 /**
143 * @return array
144 */
145 public function setDefaultValues() {
146 $defaults = [];
147
148 if (!$this->_id) {
149 $defaults['is_active'] = $defaults['is_default'] = 1;
150 return $defaults;
151 }
152 $domainID = CRM_Core_Config::domainID();
153
154 $dao = new CRM_Core_DAO_Job();
155 $dao->id = $this->_id;
156 $dao->domain_id = $domainID;
157 if (!$dao->find(TRUE)) {
158 return $defaults;
159 }
160
161 CRM_Core_DAO::storeValues($dao, $defaults);
162
163 // CRM-17686
164 if (!empty($dao->scheduled_run_date)) {
165 $ts = strtotime($dao->scheduled_run_date);
166 $defaults['scheduled_run_date'] = date("Y-m-d H:i:s", $ts);
167 }
168
169 // CRM-10708
170 // job entity thats shipped with core is all lower case.
171 // this makes sure camel casing is followed for proper working of default population.
172 if (!empty($defaults['api_entity'])) {
173 $defaults['api_entity'] = ucfirst($defaults['api_entity']);
174 }
175
176 return $defaults;
177 }
178
179 /**
180 * Process the form submission.
181 */
182 public function postProcess() {
183
184 CRM_Utils_System::flushCache();
185
186 if ($this->_action & CRM_Core_Action::DELETE) {
187 CRM_Core_BAO_Job::del($this->_id);
188 CRM_Core_Session::setStatus("", ts('Scheduled Job Deleted.'), "success");
189 return;
190 }
191
192 // using View action for Execute. Doh.
193 if ($this->_action & CRM_Core_Action::VIEW) {
194 $jm = new CRM_Core_JobManager();
195 $jm->executeJobById($this->_id);
196 $jobName = self::getJobName($this->_id);
197 CRM_Core_Session::setStatus(ts('%1 Scheduled Job has been executed. See the log for details.', [1 => $jobName]), ts("Executed"), "success");
198
199 if ($this->getContext() === 'joblog') {
200 // If we were triggered via the joblog form redirect back there when we finish
201 $redirectUrl = CRM_Utils_System::url('civicrm/admin/joblog', 'reset=1&jid=' . $this->_id);
202 }
203 else {
204 $redirectUrl = CRM_Utils_System::url('civicrm/admin/job', 'reset=1');
205 }
206 CRM_Utils_System::redirect($redirectUrl);
207 return;
208 }
209
210 $values = $this->controller->exportValues($this->_name);
211 $domainID = CRM_Core_Config::domainID();
212
213 $dao = new CRM_Core_DAO_Job();
214
215 $dao->id = $this->_id;
216 $dao->domain_id = $domainID;
217 $dao->run_frequency = $values['run_frequency'];
218 $dao->parameters = $values['parameters'];
219 $dao->name = $values['name'];
220 $dao->api_entity = $values['api_entity'];
221 $dao->api_action = $values['api_action'];
222 $dao->description = $values['description'];
223 $dao->is_active = CRM_Utils_Array::value('is_active', $values, 0);
224
225 // CRM-17686
226 $ts = strtotime($values['scheduled_run_date']);
227 // if a date/time is supplied and not in the past, then set the next scheduled run...
228 if ($ts > time()) {
229 $dao->scheduled_run_date = CRM_Utils_Date::currentDBDate($ts);
230 // warn about monthly/quarterly scheduling, if applicable
231 if (($dao->run_frequency == 'Monthly') || ($dao->run_frequency == 'Quarter')) {
232 $info = getdate($ts);
233 if ($info['mday'] > 28) {
234 CRM_Core_Session::setStatus(
235 ts('Relative month values are calculated based on the length of month(s) that they pass through.
236 The result will land on the same day of the month except for days 29-31 when the target month contains fewer days than the previous month.
237 For example, if a job is scheduled to run on August 31st, the following invocation will occur on October 1st, and then the 1st of every month thereafter.
238 To avoid this issue, please schedule Monthly and Quarterly jobs to run within the first 28 days of the month.'),
239 ts('Warning'), 'info', ['expires' => 0]);
240 }
241 }
242 }
243 // ...otherwise, if this isn't a new scheduled job, clear the next scheduled run
244 elseif ($dao->id) {
245 $job = new CRM_Core_ScheduledJob(['id' => $dao->id]);
246 $job->clearScheduledRunDate();
247 }
248
249 $dao->save();
250
251 // CRM-11143 - Give warning message if update_greetings is Enabled (is_active) since it generally should not be run automatically via execute action or runjobs url.
252 if ($values['api_action'] == 'update_greeting' && CRM_Utils_Array::value('is_active', $values) == 1) {
253 $docLink = CRM_Utils_System::docURL2("user/initial-set-up/scheduled-jobs/#job_update_greeting");
254 $msg = ts('The update greeting job can be very resource intensive and is typically not necessary to run on a regular basis. If you do choose to enable the job, we recommend you do not run it with the force=1 option, which would rebuild greetings on all records. Leaving that option absent, or setting it to force=0, will only rebuild greetings for contacts that do not currently have a value stored. %1', [1 => $docLink]);
255 CRM_Core_Session::setStatus($msg, ts('Warning: Update Greeting job enabled'), 'alert');
256 }
257
258 }
259
260 /**
261 * Get the API action aka Job Name for this scheduled job
262 * @param int $id - Id of the stored Job
263 *
264 * @return string
265 */
266 private static function getJobName($id) {
267 $entity = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Job', $id, 'api_entity');
268 $action = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Job', $id, 'api_action');
269 $name = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Job', $id, 'name');
270 return $name . ' (' . $entity . '.' . $action . ')';
271 }
272
273 }