PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.7.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.7.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.7.0, at app/Services/BookingFieldService.php

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