PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.6.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.6.0
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
fluent-booking / app / Services / BookingFieldService.php

BookingFieldService.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 1.6.0, at app/Services/BookingFieldService.php

425 lines 15.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\App\Services;
4
5 use FluentBooking\App\Models\Booking;
6 use FluentBooking\App\Models\CalendarSlot;
7 use FluentBooking\Framework\Support\Arr;
8
9 class BookingFieldService
10 {
11 public static function getCustomFieldsData($postedData, CalendarSlot $slot)
12 {
13 $customFields = self::getCustomFields($slot, true);
14
15 $errors = [];
16
17 $formattedValues = [];
18
19 foreach ($customFields as $fieldKey => $customField) {
20 $value = wp_unslash(Arr::get($postedData, $fieldKey));
21 if (Arr::isTrue($customField, 'required')) {
22 if (!$value || ($customField['type'] == 'checkbox' && $value != 'Yes')) {
23 // translators: %s is the label of the required field
24 $errors[$fieldKey . '.required'] = sprintf(__('%s is required', 'fluent-booking'), $customField['label']);
25 continue;
26 }
27 }
28
29 if (is_array($value)) {
30 if ($customField['type'] === 'multi-select') {
31 $value = array_map(function ($item) {
32 return sanitize_text_field(Arr::get($item, 'value'));
33 },$value);
34 } else if ($customField['type'] === 'file') {
35 $maxField = Arr::get($customField, 'max_file_allow', 1);
36 $value = array_slice($value, 0, $maxField);
37 $value = array_map('sanitize_text_field', $value);
38 } else {
39 $value = array_map('sanitize_text_field', $value);
40 }
41 } else if ($customField['type'] == 'textarea') {
42 $value = sanitize_textarea_field($value);
43 } else {
44 $value = sanitize_text_field($value);
45 }
46
47 $formattedValues[$fieldKey] = $value;
48 }
49
50 if ($errors) {
51 return new \WP_Error('required_field', __('Please fill up the required data', 'fluent-booking'), $errors);
52 }
53
54 return $formattedValues;
55 }
56
57 public static function getBookingFields(CalendarSlot $calendarSlot, $cached = false)
58 {
59 static $bookingFields = null;
60
61 if ($cached && $bookingFields) {
62 return $bookingFields;
63 }
64
65 $requiredIndexes = ['name', 'email', 'message', 'cancellation_reason', 'rescheduling_reason'];
66
67 $defaultFields = [
68 'name' => [
69 'index' => 1,
70 'type' => 'text',
71 'name' => 'name',
72 'label' => __('Your Name', 'fluent-booking'),
73 'required' => true,
74 'enabled' => true,
75 'system_defined' => true,
76 'disable_alter' => true,
77 'is_visible' => true,
78 'placeholder' => __('Your Name', 'fluent-booking'),
79 'help_text' => ''
80 ],
81 'email' => [
82 'index' => 2,
83 'type' => 'email',
84 'name' => 'email',
85 'label' => __('Your Email', 'fluent-booking'),
86 'required' => true,
87 'enabled' => true,
88 'system_defined' => true,
89 'disable_alter' => true,
90 'is_visible' => true,
91 'placeholder' => __('Your Email', 'fluent-booking'),
92 'help_text' => ''
93 ],
94 'message' => [
95 'index' => 3,
96 'type' => 'textarea',
97 'name' => 'message',
98 'label' => __('What is this meeting about?', 'fluent-booking'),
99 'required' => false,
100 'enabled' => true,
101 'system_defined' => true,
102 'disable_alter' => false,
103 'help_text' => ''
104 ],
105 'cancellation_reason' => [
106 'index' => 4,
107 'type' => 'textarea',
108 'name' => 'cancellation_reason',
109 'label' => __('Reason for cancellation', 'fluent-booking'),
110 'placeholder' => __('Why are you cancelling?', 'fluent-booking'),
111 'required' => true,
112 'enabled' => true,
113 'system_defined' => true,
114 'disable_alter' => false,
115 'help_text' => ''
116 ],
117 'rescheduling_reason' => [
118 'index' => 5,
119 'type' => 'textarea',
120 'name' => 'rescheduling_reason',
121 'label' => __('Reason for reschedule', 'fluent-booking'),
122 'placeholder' => __('Let others know why you need to reschedule', 'fluent-booking'),
123 'required' => true,
124 'enabled' => true,
125 'system_defined' => true,
126 'disable_alter' => false,
127 'help_text' => ''
128 ],
129 ];
130
131 if ($calendarSlot->isGuestFieldRequired()) {
132 $requiredIndexes[] = 'guests';
133 $defaultFields['guests'] = [
134 'index' => 6,
135 'type' => 'multi-guests',
136 'name' => 'guests',
137 'label' => __('Additional Guests', 'fluent-booking'),
138 'limit' => 10,
139 'required' => false,
140 'enabled' => false,
141 'system_defined' => true,
142 'disable_alter' => false
143 ];
144 }
145 if ($calendarSlot->isLocationFieldRequired()) {
146 $requiredIndexes[] = 'location';
147 $defaultFields['location'] = [
148 'index' => 7,
149 'type' => 'radio',
150 'name' => 'location',
151 'label' => __('Location', 'fluent-booking'),
152 'options' => LocationService::getLocationOptions($calendarSlot),
153 'required' => true,
154 'enabled' => true,
155 'system_defined' => true,
156 'disable_alter' => true,
157 'placeholder' => esc_attr__('Location', 'fluent-booking')
158 ];
159 } else if ($calendarSlot->isPhoneRequired()) {
160 $requiredIndexes[] = 'phone_number';
161 $defaultFields['phone_number'] = [
162 'index' => 8,
163 'type' => 'phone',
164 'name' => 'phone_number',
165 'label' => __('Your Phone Number', 'fluent-booking'),
166 'required' => true,
167 'enabled' => true,
168 'system_defined' => true,
169 'disable_alter' => true,
170 'is_sms_number' => true,
171 'help_text' => ''
172 ];
173 } else if ($calendarSlot->isAddressRequired()) {
174 $requiredIndexes[] = 'address';
175 $defaultFields['address'] = [
176 'index' => 9,
177 'type' => 'text',
178 'name' => 'address',
179 'label' => __('Your Address', 'fluent-booking'),
180 'required' => true,
181 'enabled' => true,
182 'system_defined' => true,
183 'disable_alter' => true,
184 'placeholder' => esc_attr__('Address', 'fluent-booking'),
185 'help_text' => ''
186 ];
187 }
188
189 $dbFields = $calendarSlot->getMeta('booking_fields', []);
190
191 if (!$dbFields) {
192 $dbFields = array_values($defaultFields);
193 }
194
195 $existingFields = [];
196 foreach ($dbFields as $dbField) {
197 $name = $dbField['name'];
198 $existingFields[$name] = $dbField;
199 }
200
201 if (empty($defaultFields['location'])) {
202 unset($existingFields['location']);
203 } else {
204 if (empty($existingFields['location'])) {
205 $existingFields['location'] = $defaultFields['location'];
206 } else {
207 $existingFields['location']['options'] = $defaultFields['location']['options'];
208 }
209 }
210
211 if (empty($defaultFields['phone_number'])) {
212 unset($existingFields['phone_number']);
213 }
214
215 if (empty($defaultFields['address'])) {
216 unset($existingFields['address']);
217 }
218
219 foreach ($requiredIndexes as $index) {
220 if (empty($existingFields[$index]) && !empty($defaultFields[$index])) {
221 $existingFields[$index] = $defaultFields[$index];
222 }
223 }
224
225 $paymentField = apply_filters('fluent_booking/payment_booking_field', [], $calendarSlot, $existingFields);
226
227 if (!$paymentField) {
228 unset($existingFields['payment_method']);
229 } else {
230 $existingFields['payment_method'] = $paymentField;
231 }
232
233 $existingFields['email']['disabled'] = false;
234
235 $bookingFields = apply_filters('fluent_booking/booking_fields', array_values($existingFields), $calendarSlot);
236
237 return $bookingFields;
238 }
239
240 public static function getBookingFieldLabels(CalendarSlot $calendarSlot, $enabledOnly = false)
241 {
242 $fields = self::getBookingFields($calendarSlot, true);
243
244 $labels = [];
245 foreach ($fields as $field) {
246 if ($enabledOnly && !Arr::isTrue($field, 'enabled')) {
247 continue;
248 }
249
250 $labels[$field['name']] = $field['label'];
251 }
252
253 return $labels;
254 }
255
256 public static function generateFieldName($calendarEvent, $fieldLabel)
257 {
258 $fieldName = 'custom_' . sanitize_title($fieldLabel);
259 $bookingFields = self::getBookingFields($calendarEvent);
260
261 $matched = 0;
262 foreach ($bookingFields as $field) {
263 if (strpos($field['name'], $fieldName) !== false) {
264 $matched++;
265 }
266 }
267
268 if ($matched) {
269 $fieldName .= '_' . $matched;
270 }
271 return $fieldName;
272 }
273
274 public static function maybeGenerateFieldName($calendarEvent, $fieldValue)
275 {
276 $bookingFields = self::getBookingFields($calendarEvent);
277
278 foreach ($bookingFields as $field) {
279 if ($field['name'] == $fieldValue['name'] && $field['index'] != $fieldValue['index']) {
280 return self::generateFieldName($calendarEvent, $fieldValue['label']);
281 }
282 }
283
284 return sanitize_text_field($fieldValue['name']);
285 }
286
287 public static function getFormattedCustomBookingData(Booking $booking, $htmlSupport = true, $isPublic = false)
288 {
289 $customFormData = $booking->getMeta('custom_fields_data', []);
290 if (!$customFormData) {
291 return [];
292 }
293
294 $labels = self::getBookingFieldLabels($booking->calendar_event);
295
296 $formattedData = [];
297
298 foreach ($customFormData as $dataKey => $value) {
299 $label = $labels[$dataKey] ?? $dataKey;
300
301 $formattedValue = is_array($value) ? implode(', ', $value) : $value;
302
303 $field = self::getBookingFieldByName($booking->calendar_event, $dataKey);
304
305 $fieldType = Arr::get($field, 'type');
306
307 if ($fieldType == 'file' && is_array($value)) {
308 $formattedValue = self::getUploadedFiles($value, $htmlSupport);
309 }
310
311 if ($fieldType == 'hidden') {
312 if ($isPublic) continue;
313 $formattedValue = EditorShortcodeParser::parse($formattedValue, $booking);
314 }
315
316 $formattedData[$dataKey] = [
317 'label' => $label,
318 'value' => $formattedValue
319 ];
320 }
321
322 return $formattedData;
323 }
324
325 public static function getCustomFields($calendarEvent, $withConfig = false)
326 {
327 $existingFields = $calendarEvent->getMeta('booking_fields', []);
328
329 if (!$existingFields) {
330 return [];
331 }
332
333 $customFields = [];
334
335 foreach ($existingFields as $existingField) {
336 if (Arr::get($existingField, 'system_defined') || !Arr::isTrue($existingField, 'enabled')) {
337 continue;
338 }
339 if ($withConfig) {
340 $customFields[$existingField['name']] = $existingField;
341 } else {
342 $customFields[$existingField['name']] = $existingField['label'];
343 }
344 }
345
346 return $customFields;
347 }
348
349 public static function getBookingFieldByName($calendarEvent, $name)
350 {
351 $fields = self::getBookingFields($calendarEvent, true);
352
353 foreach ($fields as $field) {
354 if (Arr::get($field, 'name') == $name) {
355 return $field;
356 }
357 }
358
359 return [];
360 }
361
362 public static function hasPhoneNumberField($fields)
363 {
364 if(!$fields) {
365 return false;
366 }
367
368 foreach ($fields as $field) {
369 if ($field['type'] == 'phone') {
370 return true;
371 } else if ($field['name'] == 'location') {
372 if (!empty($field['options'])) {
373 foreach ($field['options'] as $option) {
374 if (Arr::get($option, 'type') == 'phone_guest') {
375 return true;
376 }
377 }
378 }
379 }
380 }
381 return false;
382 }
383
384 public static function getUploadedFiles($fieldValue, $htmlSupport = true)
385 {
386 if (empty($fieldValue)) {
387 return '';
388 }
389
390 $files = array_map(function($file) use ($htmlSupport) {
391 if ($htmlSupport) {
392 return '<a href="' . esc_url($file) . '" target="_blank" download="' . esc_attr(basename($file)) . '">' . esc_html(basename($file)) . '</a>';
393 }
394 return $file;
395 }, $fieldValue);
396
397 $separator = $htmlSupport ? '<br>' : PHP_EOL;
398
399 return implode($separator, $files);
400 }
401
402 public static function validateDateFields($customFieldsData, $calendarEvent)
403 {
404 foreach ($customFieldsData as $fieldKey => $fieldValue) {
405 $field = self::getBookingFieldByName($calendarEvent, $fieldKey);
406 if ($fieldValue && Arr::get($field, 'type') == 'date') {
407 $minDate = Arr::get($field, 'min_date');
408 $maxDate = Arr::get($field, 'max_date');
409
410 $fieldValue = date('Y-m-d', strtotime($fieldValue));
411 $minDate = date('Y-m-d', strtotime($minDate ?: '1900-01-01'));
412 $maxDate = date('Y-m-d', strtotime($maxDate ?: date('Y-12-31')));
413
414 if ($minDate && $fieldValue < $minDate) {
415 return new \WP_Error('invalid_date', sprintf(__('The date for %s cannot be earlier than %s.', 'fluent-booking'), $field['label'], $minDate));
416 }
417 if ($maxDate && $fieldValue > $maxDate) {
418 return new \WP_Error('invalid_date', sprintf(__('The date for %s cannot be later than %s.', 'fluent-booking'), $field['label'], $maxDate));
419 }
420 }
421 }
422 return true;
423 }
424 }
425