Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 TO |
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 | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 | 11 | |
9b9335ed | 12 | use Civi\Api4\Event; |
aa06ad4a | 13 | use Civi\Api4\LocBlock; |
14 | use Civi\Api4\Email; | |
15 | use Civi\Api4\Phone; | |
16 | use Civi\Api4\Address; | |
9b9335ed | 17 | |
6a488035 TO |
18 | /** |
19 | * | |
20 | * | |
21 | * @package CRM | |
ca5cec67 | 22 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
23 | */ |
24 | ||
25 | /** | |
26 | * This class generates form components for processing Event Location | |
27 | * civicrm_event_page. | |
28 | */ | |
29 | class CRM_Event_Form_ManageEvent_Location extends CRM_Event_Form_ManageEvent { | |
30 | ||
9b9335ed | 31 | /** |
32 | * @var \Civi\Api4\Generic\Result | |
33 | */ | |
34 | protected $locationBlock; | |
35 | ||
6a488035 | 36 | /** |
100fef9d | 37 | * How many locationBlocks should we display? |
6a488035 TO |
38 | * |
39 | * @var int | |
40 | * @const | |
41 | */ | |
7da04cde | 42 | const LOCATION_BLOCKS = 1; |
6a488035 TO |
43 | |
44 | /** | |
100fef9d | 45 | * The variable, for storing the location array |
6a488035 TO |
46 | * |
47 | * @var array | |
48 | */ | |
be2fb01f | 49 | protected $_locationIds = []; |
6a488035 TO |
50 | |
51 | /** | |
100fef9d | 52 | * The variable, for storing location block id with event |
6a488035 TO |
53 | * |
54 | * @var int | |
55 | */ | |
56 | protected $_oldLocBlockId = 0; | |
57 | ||
58 | /** | |
66f9e52b | 59 | * Get the db values for this form. |
90b461f1 | 60 | * @var array |
6a488035 | 61 | */ |
be2fb01f | 62 | public $_values = []; |
6a488035 TO |
63 | |
64 | /** | |
66f9e52b | 65 | * Set variables up before form is built. |
6a488035 | 66 | */ |
00be9182 | 67 | public function preProcess() { |
6a488035 | 68 | parent::preProcess(); |
e4b857f8 | 69 | $this->setSelectedChild('location'); |
6a488035 TO |
70 | |
71 | $this->_values = $this->get('values'); | |
72 | if ($this->_id && empty($this->_values)) { | |
6a488035 | 73 | //get location values. |
be2fb01f | 74 | $params = [ |
6a488035 TO |
75 | 'entity_id' => $this->_id, |
76 | 'entity_table' => 'civicrm_event', | |
be2fb01f | 77 | ]; |
6a488035 TO |
78 | $this->_values = CRM_Core_BAO_Location::getValues($params); |
79 | ||
80 | //get event values. | |
be2fb01f | 81 | $params = ['id' => $this->_id]; |
6a488035 TO |
82 | CRM_Event_BAO_Event::retrieve($params, $this->_values); |
83 | $this->set('values', $this->_values); | |
84 | } | |
be84b210 | 85 | |
86 | //location blocks. | |
87 | CRM_Contact_Form_Location::preProcess($this); | |
6a488035 TO |
88 | } |
89 | ||
90 | /** | |
3bdf1f3a | 91 | * Set default values for the form. |
6a488035 | 92 | * |
3bdf1f3a | 93 | * Note that in edit/view mode the default values are retrieved from the database. |
6a488035 | 94 | */ |
00be9182 | 95 | public function setDefaultValues() { |
6a488035 TO |
96 | $defaults = $this->_values; |
97 | ||
5d92a7e7 | 98 | if (!empty($defaults['loc_block_id'])) { |
6a488035 TO |
99 | $defaults['loc_event_id'] = $defaults['loc_block_id']; |
100 | $countLocUsed = CRM_Event_BAO_Event::countEventsUsingLocBlockId($defaults['loc_block_id']); | |
62a0f5a1 | 101 | $this->assign('locUsed', $countLocUsed); |
6a488035 TO |
102 | } |
103 | ||
104 | $config = CRM_Core_Config::singleton(); | |
105 | if (!isset($defaults['address'][1]['country_id'])) { | |
106 | $defaults['address'][1]['country_id'] = $config->defaultContactCountry; | |
107 | } | |
03e04002 | 108 | |
6a488035 TO |
109 | if (!isset($defaults['address'][1]['state_province_id'])) { |
110 | $defaults['address'][1]['state_province_id'] = $config->defaultContactStateProvince; | |
111 | } | |
112 | ||
6a488035 TO |
113 | $defaults['location_option'] = $this->_oldLocBlockId ? 2 : 1; |
114 | ||
115 | return $defaults; | |
116 | } | |
117 | ||
118 | /** | |
66f9e52b | 119 | * Add local and global form rules. |
6a488035 | 120 | */ |
00be9182 | 121 | public function addRules() { |
be2fb01f | 122 | $this->addFormRule(['CRM_Event_Form_ManageEvent_Location', 'formRule']); |
6a488035 TO |
123 | } |
124 | ||
125 | /** | |
66f9e52b | 126 | * Global validation rules for the form. |
6a488035 | 127 | * |
d4dd1e85 TO |
128 | * @param array $fields |
129 | * Posted values of the form. | |
6a488035 | 130 | * |
a6c01b45 CW |
131 | * @return array |
132 | * list of errors to be posted back to the form | |
6a488035 | 133 | */ |
00be9182 | 134 | public static function formRule($fields) { |
6a488035 | 135 | // check for state/country mapping |
1273d77c | 136 | $errors = CRM_Contact_Form_Edit_Address::formRule($fields); |
6a488035 TO |
137 | |
138 | return empty($errors) ? TRUE : $errors; | |
139 | } | |
140 | ||
141 | /** | |
3bdf1f3a | 142 | * Function to build location block. |
6a488035 TO |
143 | */ |
144 | public function buildQuickForm() { | |
59f8bad6 CW |
145 | CRM_Contact_Form_Edit_Address::buildQuickForm($this, 1); |
146 | CRM_Contact_Form_Edit_Email::buildQuickForm($this, 1); | |
147 | CRM_Contact_Form_Edit_Email::buildQuickForm($this, 2); | |
148 | CRM_Contact_Form_Edit_Phone::buildQuickForm($this, 1); | |
149 | CRM_Contact_Form_Edit_Phone::buildQuickForm($this, 2); | |
6a488035 TO |
150 | |
151 | $this->applyFilter('__ALL__', 'trim'); | |
152 | ||
6a488035 TO |
153 | //fix for CRM-1971 |
154 | $this->assign('action', $this->_action); | |
155 | ||
156 | if ($this->_id) { | |
9b9335ed | 157 | $this->locationBlock = Event::get() |
158 | ->addWhere('id', '=', $this->_id) | |
84ad7693 | 159 | ->setSelect(['loc_block_id.*', 'loc_block_id']) |
9b9335ed | 160 | ->execute()->first(); |
161 | $this->_oldLocBlockId = $this->locationBlock['loc_block_id']; | |
6a488035 TO |
162 | } |
163 | ||
164 | // get the list of location blocks being used by other events | |
03e04002 | 165 | |
6a488035 TO |
166 | $locationEvents = CRM_Event_BAO_Event::getLocationEvents(); |
167 | // remove duplicates and make sure that the duplicate entry with key as | |
168 | // loc_block_id of this event (this->_id) is preserved | |
a7488080 | 169 | if (!empty($locationEvents[$this->_oldLocBlockId])) { |
6a488035 TO |
170 | $possibleDuplicate = $locationEvents[$this->_oldLocBlockId]; |
171 | $locationEvents = array_flip(array_unique($locationEvents)); | |
a7488080 | 172 | if (!empty($locationEvents[$possibleDuplicate])) { |
6a488035 TO |
173 | $locationEvents[$possibleDuplicate] = $this->_oldLocBlockId; |
174 | } | |
175 | $locationEvents = array_flip($locationEvents); | |
176 | } | |
177 | else { | |
178 | $locationEvents = array_unique($locationEvents); | |
179 | } | |
180 | ||
6a488035 TO |
181 | if (!empty($locationEvents)) { |
182 | $this->assign('locEvents', TRUE); | |
be2fb01f | 183 | $optionTypes = [ |
353ffa53 | 184 | '1' => ts('Create new location'), |
6a488035 | 185 | '2' => ts('Use existing location'), |
be2fb01f | 186 | ]; |
6a488035 | 187 | |
62a0f5a1 | 188 | $this->addRadio('location_option', ts("Choose Location"), $optionTypes); |
6a488035 TO |
189 | |
190 | if (!isset($locationEvents[$this->_oldLocBlockId]) || (!$this->_oldLocBlockId)) { | |
be2fb01f | 191 | $locationEvents = ['' => ts('- select -')] + $locationEvents; |
6a488035 | 192 | } |
be2fb01f | 193 | $this->add('select', 'loc_event_id', ts('Use Location'), $locationEvents, FALSE, ['class' => 'crm-select2']); |
6a488035 TO |
194 | } |
195 | $this->addElement('advcheckbox', 'is_show_location', ts('Show Location?')); | |
196 | parent::buildQuickForm(); | |
197 | } | |
198 | ||
199 | /** | |
66f9e52b | 200 | * Process the form submission. |
6a488035 TO |
201 | */ |
202 | public function postProcess() { | |
203 | $params = $this->exportValues(); | |
204 | $deleteOldBlock = FALSE; | |
205 | ||
51d78c5d CW |
206 | // If 'Use existing location' is selected. |
207 | if (CRM_Utils_Array::value('location_option', $params) == 2) { | |
208 | ||
209 | /* | |
210 | * If there is an existing LocBlock and the selected LocBlock is different, | |
211 | * flag the existing LocBlock for deletion. | |
212 | */ | |
213 | if ($this->_oldLocBlockId && !empty($params['loc_event_id']) && | |
214 | ($params['loc_event_id'] != $this->_oldLocBlockId) | |
215 | ) { | |
216 | $deleteOldBlock = TRUE; | |
217 | } | |
218 | ||
219 | /* | |
220 | * Always update the loc_block_id in this Event so that LocBlock update | |
221 | * affects the selected LocBlock and not the previous one - whether or not | |
222 | * there is a previous LocBlock. | |
223 | */ | |
6a488035 TO |
224 | CRM_Core_DAO::setFieldValue('CRM_Event_DAO_Event', $this->_id, |
225 | 'loc_block_id', $params['loc_event_id'] | |
226 | ); | |
51d78c5d | 227 | |
6a488035 TO |
228 | } |
229 | ||
51d78c5d CW |
230 | /* |
231 | * If there is an existing LocBlock and 'Create new location' is selected, | |
232 | * set the loc_block_id for this Event to null so that an update results in | |
233 | * creating a new LocBlock. | |
234 | */ | |
6a488035 TO |
235 | if ($this->_oldLocBlockId && (CRM_Utils_Array::value('location_option', $params) == 1)) { |
236 | $deleteOldBlock = TRUE; | |
237 | CRM_Core_DAO::setFieldValue('CRM_Event_DAO_Event', $this->_id, | |
238 | 'loc_block_id', 'null' | |
239 | ); | |
240 | } | |
241 | ||
51d78c5d CW |
242 | /* |
243 | * If there is a previous LocBlock and we have determined that it should be | |
244 | * deleted, go ahead and do so now. The method that is called will only delete | |
245 | * the LocBlock if it is not being used by another Event. | |
246 | */ | |
6a488035 TO |
247 | if ($this->_oldLocBlockId && $deleteOldBlock) { |
248 | CRM_Event_BAO_Event::deleteEventLocBlock($this->_oldLocBlockId, $this->_id); | |
249 | } | |
250 | ||
51d78c5d CW |
251 | // Assume a new LocBlock is needed. |
252 | $isUpdateToExistingLocationBlock = FALSE; | |
253 | ||
254 | /* | |
255 | * If there is a previous LocBlock and it was not deleted, check if the new | |
256 | * LocBlock ID matches the previous one. If so, then it needs to be updated. | |
257 | */ | |
258 | if (!empty($this->locationBlock['loc_block_id']) && !$deleteOldBlock) { | |
259 | if (!empty($params['loc_event_id']) && (int) $params['loc_event_id'] === $this->locationBlock['loc_block_id']) { | |
260 | $isUpdateToExistingLocationBlock = TRUE; | |
261 | } | |
262 | } | |
263 | ||
264 | /* | |
265 | * If 'Use existing location' is selected and there isn't a previous LocBlock | |
266 | * but a LocBlock has been selected, then that LocBlock should be updated. | |
267 | * In order to do so, the IDs of the Address, Phone and Email "Blocks" have | |
268 | * to be retrieved and added in to the elements in the $params array. | |
269 | */ | |
270 | if (CRM_Utils_Array::value('location_option', $params) == 2) { | |
271 | if (empty($this->locationBlock['loc_block_id']) && !empty($params['loc_event_id'])) { | |
272 | $isUpdateToExistingLocationBlock = TRUE; | |
273 | $existingLocBlock = LocBlock::get() | |
274 | ->addWhere('id', '=', (int) $params['loc_event_id']) | |
275 | ->setCheckPermissions(FALSE) | |
276 | ->execute()->first(); | |
277 | } | |
278 | } | |
279 | ||
280 | /* | |
281 | * It should be impossible for there to be no default location type. | |
282 | * Consider removing this handling. | |
283 | */ | |
9b9335ed | 284 | $defaultLocationTypeID = CRM_Core_BAO_LocationType::getDefault()->id ?? 1; |
aa06ad4a | 285 | |
be2fb01f | 286 | foreach ([ |
9b9335ed | 287 | 'address' => $params['address'], |
288 | 'phone' => $params['phone'], | |
289 | 'email' => $params['email'], | |
290 | ] as $block => $locationEntities) { | |
531b6c9e | 291 | |
9b9335ed | 292 | $params[$block][1]['is_primary'] = 1; |
293 | foreach ($locationEntities as $index => $locationEntity) { | |
51d78c5d CW |
294 | |
295 | $fieldKey = (int) $index === 1 ? '_id' : '_2_id'; | |
296 | ||
297 | // Assume there's no Block ID. | |
298 | $blockId = FALSE; | |
299 | ||
300 | // Check the existing LocBlock for an ID. | |
301 | if (!empty($this->locationBlock['loc_block_id.' . $block . $fieldKey])) { | |
302 | $blockId = $this->locationBlock['loc_block_id.' . $block . $fieldKey]; | |
303 | } | |
304 | else { | |
305 | // Check the queried LocBlock for an ID. | |
306 | if (!empty($existingLocBlock[$block . $fieldKey])) { | |
307 | $blockId = $existingLocBlock[$block . $fieldKey]; | |
308 | } | |
309 | } | |
310 | ||
311 | /* | |
312 | * Unsetting the array element excludes the Block from being updated and | |
313 | * removes it from the LocBlock. However, the intention of clearing a Block | |
314 | * is presumably to delete it. | |
315 | */ | |
7af49a64 | 316 | if (!$this->isLocationHasData($block, $locationEntity)) { |
317 | unset($params[$block][$index]); | |
51d78c5d CW |
318 | if (!empty($blockId)) { |
319 | // The Block can be deleted here. | |
320 | } | |
7af49a64 | 321 | continue; |
322 | } | |
51d78c5d | 323 | |
9b9335ed | 324 | $params[$block][$index]['location_type_id'] = $defaultLocationTypeID; |
51d78c5d CW |
325 | |
326 | // Assign the existing Block ID if an update is needed. | |
327 | if ($isUpdateToExistingLocationBlock && !empty($blockId)) { | |
328 | $params[$block][$index]['id'] = $blockId; | |
045bc380 | 329 | } |
6a488035 | 330 | } |
51d78c5d | 331 | |
6a488035 | 332 | } |
51d78c5d CW |
333 | |
334 | // Update the Blocks. | |
7af49a64 | 335 | $addresses = empty($params['address']) ? [] : Address::save(FALSE)->setRecords($params['address'])->execute(); |
336 | $emails = empty($params['email']) ? [] : Email::save(FALSE)->setRecords($params['email'])->execute(); | |
337 | $phones = empty($params['phone']) ? [] : Phone::save(FALSE)->setRecords($params['phone'])->execute(); | |
aa06ad4a | 338 | |
51d78c5d CW |
339 | // Build the LocBlock record. |
340 | $record = [ | |
341 | 'email_id' => $emails[0]['id'] ?? NULL, | |
342 | 'address_id' => $addresses[0]['id'] ?? NULL, | |
343 | 'phone_id' => $phones[0]['id'] ?? NULL, | |
344 | 'email_2_id' => $emails[1]['id'] ?? NULL, | |
345 | 'address_2_id' => $addresses[1]['id'] ?? NULL, | |
346 | 'phone_2_id' => $phones[1]['id'] ?? NULL, | |
347 | ]; | |
348 | ||
349 | // Maybe trigger LocBlock update. | |
350 | if ($isUpdateToExistingLocationBlock) { | |
351 | $record['id'] = (int) $params['loc_event_id']; | |
352 | } | |
353 | ||
354 | // Update the LocBlock. | |
355 | $params['loc_block_id'] = LocBlock::save(FALSE)->setRecords([$record])->execute()->first()['id']; | |
356 | ||
357 | // Finally update Event params. | |
6a488035 TO |
358 | $params['id'] = $this->_id; |
359 | CRM_Event_BAO_Event::add($params); | |
360 | ||
51d78c5d | 361 | // Update tab "disabled" CSS class. |
5d92a7e7 | 362 | $this->ajaxResponse['tabValid'] = TRUE; |
6a488035 TO |
363 | parent::endPostProcess(); |
364 | } | |
6a488035 TO |
365 | |
366 | /** | |
367 | * Return a descriptive name for the page, used in wizard header | |
368 | * | |
369 | * @return string | |
6a488035 TO |
370 | */ |
371 | public function getTitle() { | |
372 | return ts('Event Location'); | |
373 | } | |
96025800 | 374 | |
7af49a64 | 375 | /** |
376 | * Is there some data to save for the given entity | |
377 | * | |
378 | * @param string $block | |
379 | * @param array $locationEntity | |
380 | * | |
381 | * @return bool | |
382 | */ | |
383 | protected function isLocationHasData(string $block, array $locationEntity): bool { | |
384 | if ($block === 'email') { | |
385 | return !empty($locationEntity['email']); | |
386 | } | |
387 | if ($block === 'phone') { | |
388 | return !empty($locationEntity['phone']); | |
389 | } | |
390 | foreach ($locationEntity as $value) { | |
391 | if (!empty($value)) { | |
392 | return TRUE; | |
393 | } | |
394 | } | |
395 | return FALSE; | |
396 | } | |
397 | ||
6a488035 | 398 | } |