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