PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.2
Booktics – Appointment Booking Calendar for Service Businesses v1.0.2
1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.2 1.0.3 All 31 releases
booktics / core / service / controllers / service-controller.php

service-controller.php in Booktics – Appointment Booking Calendar for Service Businesses 1.0.2, at core/service/controllers/service-controller.php

677 lines 24.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Booktics\Service\Controllers;
4
5 use Booktics\Abstracts\Base_Rest_Controller;
6 use Booktics\Models\Service_Model;
7 use Booktics\Models\Team_Member_Model;
8 use Booktics\Services\Schedule_Manager;
9 use Booktics\Services\Schedule_Record;
10 use Booktics\Taxonomy\Category;
11 use Exception;
12 use WP_Error;
13 use WP_HTTP_Response;
14 use WP_REST_Server;
15
16 /**
17 * Service controller
18 *
19 * @package Booktics/Service
20 */
21 class Service_Controller extends Base_Rest_Controller {
22 /**
23 * Endpoint namespace
24 *
25 * @var string
26 */
27 protected $namespace = 'booktics/v1';
28
29 /**
30 * Route name
31 *
32 * @var string
33 */
34 protected $base = 'services';
35
36 /**
37 * Register routes
38 *
39 * @return void
40 */
41 public function register_routes(): void {
42 register_rest_route(
43 $this->namespace, $this->base, array(
44 array(
45 'methods' => WP_REST_Server::CREATABLE,
46 'callback' => array( $this, 'create_item' ),
47 'permission_callback' => array(
48 $this,
49 'create_item_permissions_check',
50 ),
51 ),
52 )
53 );
54
55 register_rest_route(
56 $this->namespace, $this->base, array(
57 array(
58 'methods' => WP_REST_Server::READABLE,
59 'callback' => array( $this, 'get_items' ),
60 'permission_callback' => array(
61 $this,
62 'get_items_permissions_check',
63 ),
64 ),
65 )
66 );
67
68 register_rest_route(
69 $this->namespace, $this->base, array(
70 array(
71 'methods' => WP_REST_Server::DELETABLE,
72 'callback' => array( $this, 'delete_items' ),
73 'permission_callback' => array(
74 $this,
75 'delete_items_permissions_check',
76 ),
77 ),
78 )
79 );
80
81 register_rest_route(
82 $this->namespace, $this->base . '/(?P<id>[\d]+)', array(
83 array(
84 'methods' => WP_REST_Server::READABLE,
85 'callback' => array( $this, 'get_item' ),
86 'permission_callback' => array(
87 $this,
88 'get_item_permissions_check',
89 ),
90 ),
91 )
92 );
93
94 register_rest_route(
95 $this->namespace, $this->base . '/(?P<id>[\d]+)', array(
96 array(
97 'methods' => WP_REST_Server::EDITABLE,
98 'callback' => array( $this, 'update_item' ),
99 'permission_callback' => array(
100 $this,
101 'update_item_permissions_check',
102 ),
103 ),
104 )
105 );
106
107 register_rest_route(
108 $this->namespace, $this->base . '/(?P<id>[\d]+)', array(
109 array(
110 'methods' => WP_REST_Server::DELETABLE,
111 'callback' => array( $this, 'delete_item' ),
112 'permission_callback' => array(
113 $this,
114 'delete_item_permissions_check',
115 ),
116 ),
117 )
118 );
119
120 register_rest_route(
121 $this->namespace, $this->base . '/(?P<id>[\d]+)/clone', array(
122 array(
123 'methods' => WP_REST_Server::CREATABLE,
124 'callback' => array( $this, 'clone_item' ),
125 'permission_callback' => array(
126 $this,
127 'create_item_permissions_check',
128 ),
129 ),
130 )
131 );
132 }
133
134 /**
135 * Get one item from the collection.
136 *
137 * @param $request
138 *
139 * @return WP_HTTP_Response
140 */
141 public function get_item( $request ) {
142 $id = intval( $request['id'] );
143
144 $service = Service_Model::find( $id );
145
146 if ( ! $service ) {
147 return $this->error( __( 'Service not found', 'booktics' ), 404 );
148 }
149 $service = $service->to_array();
150
151 $team_member_ids = is_array( $service['team_member'] )
152 ? array_unique( $service['team_member'] ) : array( $service['team_member'] );
153 $service['team_member_details'] = $this->team_member_details( $team_member_ids );
154 $service['team_member'] = $team_member_ids;
155
156 $category_ids = is_array( $service['categories'] )
157 ? array_unique( $service['categories'] ) : array( $service['categories'] );
158 $service['category_details'] = $this->category_details( $category_ids );
159 $service['categories'] = $category_ids;
160
161 $schedule_record = ( new Schedule_Record() )
162 ->get_schedules( $id, 'service' );
163 $service['schedule'] = empty( $schedule_record['schedule'] ) ? (object) array()
164 : $schedule_record['schedule'];
165
166 $service['custom'] = $schedule_record['custom'];
167 $service['holiday'] = $schedule_record['holiday'];
168 $service['shortcode'] = '[booktics-service-view id="' . $service['id'] . '"]';
169 $service = apply_filters( 'booktics_service_format', $service );
170
171 return $this->response( $service );
172 }
173
174 /**
175 * Check if a given request has access to get a specific item.
176 *
177 * @param $request
178 *
179 * @return WP_Error
180 */
181 public function get_item_permissions_check( $request ): bool {
182 return true;
183 }
184
185 /**
186 * Get a collection of items.
187 *
188 * @param $request
189 *
190 * @return WP_HTTP_Response
191 */
192 public function get_items( $request ) {
193 $per_page = ! empty( $request['per_page'] ) ? intval( $request['per_page'] ) : 10;
194 $paged = ! empty( $request['paged'] ) ? intval( $request['paged'] ) : 1;
195
196 $args = array(
197 'per_page' => $per_page,
198 'paged' => $paged,
199 'meta_query' => array(),
200 );
201
202 if ( ! empty( $request['team_member_id'] ) ) {
203 $args['meta_query'][] = array(
204 'key' => 'team_member',
205 'value' => sprintf( 'i:%d;', intval( $request['team_member_id'] ) ),
206 'compare' => 'LIKE',
207 );
208 }
209
210 if ( ! empty( $request['category_id'] ) ) {
211 $args['meta_query'][] = array(
212 'key' => 'categories',
213 'value' => sprintf( 'i:%d;', intval( $request['category_id'] ) ),
214 'compare' => 'LIKE',
215 );
216 }
217
218 if ( ! empty( $request['search'] ) ) {
219 $args['s'] = sanitize_text_field( $request['search'] );
220 }
221
222 if ( ! empty( $args['meta_query'] ) ) {
223 $args['meta_query']['relation'] = 'AND';
224 }
225
226 $data = Service_Model::paginate( $per_page, $paged, $args );
227
228 if ( ! $data ) {
229 return $this->error( __( 'No service found', 'booktics' ), 404 );
230 }
231
232 if ( ! empty( $data['items'] ) ) {
233 $enhanced_items = array();
234 foreach ( $data['items'] as $service ) {
235 $service_array = $service->to_array();
236 if ( ! empty( $service_array['team_member'] ) ) {
237 $team_member_ids = is_array( $service->team_member ) ? array_unique( $service->team_member ) : array( $service->team_member );
238 $service->team_member = $team_member_ids;
239 $service_array['team_member_details'] = $this->team_member_details( $team_member_ids );
240 }
241
242 if ( ! empty( $service_array['categories'] ) ) {
243 $category_ids = is_array( $service->categories ) ? array_unique( $service->categories ) : array( $service->categories );
244 $service->categories = $category_ids;
245 $service_array['category_details'] = $this->category_details( $category_ids );
246 }
247 $service_array['shortcode'] = '[booktics-service-view id="' . $service_array['id'] . '"]';
248 $service_array = apply_filters( 'booktics_service_format', $service_array );
249 $enhanced_items[] = $service_array;
250 }
251 $data['items'] = $enhanced_items;
252 }
253
254 return $this->response( $data );
255 }
256
257 /**
258 * Check if a given request has access to get items.
259 *
260 * @param $request
261 *
262 * @return WP_Error
263 */
264 public function get_items_permissions_check( $request ): bool {
265 return true;
266 }
267
268 /**
269 * Create one item from the collection.
270 *
271 * @param $request
272 *
273 * @return WP_HTTP_Response
274 * @throws Exception
275 */
276 public function create_item( $request ) {
277 $data = $this->prepare_item_for_database( $request );
278 if ( is_wp_error( $data ) ) {
279 return $this->error( $data->get_error_message() );
280 }
281
282 $service = Service_Model::create( $data );
283
284 do_action( 'booktics_service_created', $service, $request );
285
286 if ( is_wp_error( $service ) ) {
287 return $this->error( $service->get_error_message() );
288 }
289 $service = $service->to_array();
290 $service['shortcode'] = '[booktics-service-view id="' . $service['id'] . '"]';
291 $service['category_details'] = array();
292 $service['team_member_details'] = array();
293 $service = apply_filters( 'booktics_service_format', $service );
294
295 return $this->response( $service, __( 'Successfully created service', 'booktics' ) );
296 }
297
298 /**
299 * Check if a given request has access to create items.
300 *
301 * @param $request
302 *
303 * @return WP_Error
304 */
305 public function create_item_permissions_check( $request ): bool {
306 return true;
307 }
308
309 /**
310 * Update one item from the collection.
311 *
312 * @param $request
313 *
314 * @return WP_HTTP_Response
315 * @throws Exception
316 */
317 public function update_item( $request ) {
318 $id = (int) $request->get_param( 'id' );
319 $data = $this->prepare_item_for_database( $request );
320
321 if ( is_wp_error( $data ) ) {
322 return $this->error( $data->get_error_message() );
323 }
324
325 $service = Service_Model::find( $id );
326
327 if ( ! $service ) {
328 return $this->error( __( 'Service not found', 'booktics' ), 404 );
329 }
330
331 $result = $service->update( $data );
332
333 if ( is_wp_error( $result ) ) {
334 return $this->error( $result->get_error_message() );
335 }
336
337 if ( ! empty( $data['team_member'] ) && is_array( $data['team_member'] ) ) {
338 foreach ( $data['team_member'] as $team_member_id ) {
339 $team_member_model = ( new Team_Member_Model( $team_member_id ) );
340 $team_member = $team_member_model->find( $team_member_id );
341 $team_member_services = $team_member->services == '' ? array() : $team_member->services;
342
343 if ( ! in_array( (int) $id, $team_member_services ) ) {
344 $team_member_services[] = (int) $id;
345 if ( $team_member ) {
346 $team_member->update(
347 array(
348 'services' => $team_member_services,
349 )
350 );
351 }
352 }
353 }
354
355 // Remove service from other team members
356
357 $other_team_members = ( new Team_Member_Model() )
358 ->where( 'services', $id, 'LIKE' )
359 ->all( array() );
360
361 if ( ! empty( $other_team_members['items'] ) ) {
362 foreach ( $other_team_members['items'] as $other_team_member ) {
363 if ( ! in_array( $other_team_member['id'], $data['team_member'] ) ) {
364 $other_services = $other_team_member['services'];
365 if ( ( $key = array_search( $id, $other_services ) ) !== false ) {
366 unset( $other_services[ $key ] );
367 ( new Team_Member_Model( $other_team_member['id'] ) )->update(
368 array(
369 'services' => array_values( $other_services ),
370 )
371 );
372 }
373 }
374 }
375 }
376 }
377
378 $input_data = json_decode( $request->get_body(), true );
379 if ( isset( $input_data['schedule'] ) || isset( $input_data['custom'] ) || isset( $input_data['holiday'] ) ) {
380 $service_schedule = Schedule_Manager::make( $input_data );
381 $service_schedule->with_service_id( $request['id'] );
382 $service_schedule->save();
383 }
384
385 do_action( 'booktics_service_updated', $service, $request );
386
387 $response = Service_Model::find( $id )->to_array();
388 $response['shortcode'] = '[booktics-service-view id="' . $response['id'] . '"]';
389 $response['team_member_details'] = $this->team_member_details( $response['team_member'] );
390 if ( ! empty( $response['categories'] ) ) {
391 $category_ids = is_array( $response['categories'] ) ? $response['categories'] : array( $response['categories'] );
392 $response['category_details'] = $this->category_details( $category_ids );
393 }
394 $response = apply_filters( 'booktics_service_format', $response );
395
396 return $this->response( $response, __( 'Successfully updated service', 'booktics' ) );
397 }
398
399 /**
400 * Check if a given request has access to update a specific item.
401 *
402 * @param $request
403 *
404 * @return WP_Error
405 */
406 public function update_item_permissions_check( $request ) {
407 return true;
408 }
409
410 /**
411 * Delete one item from the collection.
412 *
413 * @param $request
414 *
415 * @return WP_HTTP_Response
416 */
417 public function delete_item( $request ) {
418 $id = intval( $request['id'] );
419
420 $service = Service_Model::find( $id );
421
422 if ( ! $service ) {
423 return $this->error( __( 'Service not found', 'booktics' ), 404 );
424 }
425
426 $deleted = $service->delete();
427
428 if ( is_wp_error( $deleted ) ) {
429 return $this->error( $deleted->get_error_message() );
430 }
431
432 return $this->response( (array) $service, __( 'Successfully deleted service', 'booktics' ) );
433 }
434
435 /**
436 * Check if a given request has access to delete a specific item.
437 *
438 * @param $request
439 *
440 * @return WP_Error
441 */
442 public function delete_item_permissions_check( $request ) {
443 return current_user_can( 'manage_options' );
444 }
445
446 /**
447 * Delete a collection of items
448 *
449 * @param $request
450 *
451 * @return WP_HTTP_Response
452 */
453 public function delete_items( $request ) {
454 $ids = $request['ids'];
455
456 if ( ! is_array( $ids ) ) {
457 return $this->error( __( 'Ids should be an array of items ids', 'booktics' ) );
458 }
459
460 $count = 0;
461 $total = count( $ids );
462
463 foreach ( $ids as $id ) {
464 $service = Service_Model::find( $id );
465
466 if ( $service ) {
467 $service->delete();
468 ++$count;
469 }
470 }
471
472 if ( $count === 0 ) {
473 return $this->error( __( 'No item deleted.', 'booktics' ) );
474 }
475
476 $message = sprintf( 'Deleted %d items of %d', $count, $total );
477
478 return $this->response( array(), $message );
479 }
480
481 /**
482 * Check if a given request has access to delete a collection of items.
483 *
484 * @param $request
485 *
486 * @return WP_Error
487 */
488 public function delete_items_permissions_check( $request ) {
489 return current_user_can( 'manage_options' );
490 }
491
492 /**
493 * Prepare the item for create or update operation.
494 *
495 * @param $request
496 *
497 * @return WP_Error
498 */
499 public function prepare_item_for_database( $request ) {
500 $data = json_decode( $request->get_body(), true );
501 $validate = booktics_validate(
502 $data, array(
503 'title' => array(
504 'required',
505 ),
506 )
507 );
508
509 if ( is_wp_error( $validate ) ) {
510 return $validate;
511 }
512
513 $data['title'] = ! empty( $data['title'] ) ? sanitize_text_field( $data['title'] ) : '';
514 $data['description'] = ! empty( $data['description'] ) ? sanitize_text_field( $data['description'] ) : '';
515 $data['content'] = ! empty( $data['content'] ) ? sanitize_text_field( $data['content'] ) : '';
516 $data['link'] = ! empty( $data['link'] ) ? sanitize_text_field( $data['link'] ) : '';
517 $data['image'] = ! empty( $data['image'] ) ? esc_url_raw( $data['image'] ) : '';
518 $data['image_id'] = ! empty( $data['image_id'] ) ? esc_url_raw( $data['image_id'] ) : '';
519 $data['interval_time'] = ! empty( $data['interval_time'] ) ? sanitize_text_field( $data['interval_time'] ) : '';
520 $data['before_buffer_time'] = ! empty( $data['before_buffer_time'] ) ? sanitize_text_field( $data['before_buffer_time'] ) : '';
521 $data['status'] = ! empty( $data['status'] ) ? sanitize_text_field( $data['status'] ) : 'deactive';
522 $data['team_member'] = empty( $data['team_member'] ) ? array() : array_unique( $data['team_member'] );
523 $data['categories'] = empty( $data['categories'] ) ? array() : array_unique( $data['categories'] );
524 $sanitized_durations = array();
525 if ( ! empty( $data['additional_durations'] ) ) {
526 foreach ( $data['additional_durations'] as $duration ) {
527 if ( is_array( $duration ) ) {
528 $sanitized_durations[] = array(
529 'id' => ! empty( $duration['id'] ) ? sanitize_text_field( $duration['id'] ) : '',
530 'name' => ! empty( $duration['name'] ) ? sanitize_text_field( $duration['name'] ) : '',
531 'duration_time' => ! empty( $duration['duration_time'] ) ? sanitize_text_field( $duration['duration_time'] ) : '',
532 'duration_unit' => ! empty( $duration['duration_unit'] ) ? sanitize_text_field( $duration['duration_unit'] ) : '',
533 'charge_amount' => ! empty( $duration['charge_amount'] ) ? (float) number_format( (float) $duration['charge_amount'], 4, '.', '' ) : '0.0000',
534 'deposit_amount' => ! empty( $duration['deposit_amount'] ) ? (float) number_format( (float) $duration['deposit_amount'], 4, '.', '' ) : '0.0000',
535 );
536 }
537 }
538 } else {
539 $sanitized_durations = array(
540 array(
541 'id' => 'default',
542 'name' => 'default',
543 'duration_time' => '30',
544 'duration_unit' => 'min',
545 'charge_amount' => '0.0000',
546 'deposit_amount' => '0.0000',
547 ),
548 );
549 }
550 $data['additional_durations'] = $sanitized_durations;
551 $data = apply_filters( 'booktics_prepare_service_custom_fields', $data );
552 $image_url = $request->get_param( 'image' );
553 if ( $image_url ) {
554 $data['image'] = esc_url_raw( $image_url );
555 }
556
557 return $data;
558 }
559
560 /**
561 * Clone service from the record.
562 *
563 * @param $request
564 *
565 * @return WP_HTTP_Response
566 * @throws Exception
567 */
568 public function clone_item( $request ) {
569 $id = intval( $request['id'] );
570
571 $service = Service_Model::find( $id );
572
573 if ( ! $service ) {
574 return $this->error( __( 'Service not found', 'booktics' ), 404 );
575 }
576
577 $cloned = Service_Model::create(
578 array(
579 'title' => $service->title . __( ' Copy', 'booktics' ),
580 'description' => $service->description,
581 'content' => $service->content,
582 'image' => $service->image,
583 'image_id' => $service->image_id,
584 'categories' => $service->categories,
585 'interval_time' => $service->interval_time,
586 'before_buffer_time' => $service->before_buffer_time,
587 'after_buffer_time' => $service->after_buffer_time,
588 'team_member' => $service->team_member,
589 'show_end_time' => $service->show_end_time,
590 'additional_durations' => $service->additional_durations,
591 'enable_custom_holiday' => $service->enable_custom_holiday,
592 'enable_custom_schedule' => $service->enable_custom_schedule,
593 'enable_additional_service_duration' => $service->enable_additional_service_duration,
594 'custom_field' => $service->custom_field,
595 'extra_services' => $service->extra_services,
596 )
597 );
598
599 if ( is_wp_error( $cloned ) ) {
600 return $this->error( $cloned->get_error_message() );
601 }
602
603 $schedule_record = ( new Schedule_Record() )
604 ->get_schedules( $id, 'service' );
605 $schedule_data['schedule'] = $schedule_record['schedule'];
606 $schedule_data['custom'] = $schedule_record['custom'];
607 $schedule_data['holiday'] = $schedule_record['holiday'];
608
609 $service_schedule = Schedule_Manager::make( $schedule_data );
610 $service_schedule->with_service_id( $cloned->id );
611 $service_schedule->save();
612
613 $team_member_details = $this->team_member_details( $service->team_member );
614 $cloned = $cloned->to_array();
615 $cloned['team_member_details'] = $team_member_details;
616
617 $clone_schedule_record = ( new Schedule_Record() )
618 ->get_schedules( $cloned['id'], 'service' );
619 $cloned['schedule'] = empty( $clone_schedule_record['schedule'] ) ? (object) array()
620 : $clone_schedule_record['schedule'];
621 $cloned['custom'] = $clone_schedule_record['custom'];
622 $cloned['holiday'] = $clone_schedule_record['holiday'];
623 $cloned = apply_filters( 'booktics_service_format', $cloned );
624
625 return $this->response( $cloned, __( 'Successfully cloned service', 'booktics' ) );
626 }
627
628 /**
629 * Map team member details
630 *
631 * @param $team_member_ids
632 *
633 * @return array
634 */
635 private function team_member_details( $team_member_ids ): array {
636 $team_member_details = array();
637 foreach ( $team_member_ids as $team_member_id ) {
638 $team_member = ( new Team_Member_Model() )->find( $team_member_id );
639 if ( $team_member ) {
640 $team_member = $team_member->to_array();
641 $team_member_details[] = array(
642 'id' => $team_member['id'],
643 'display_name' => $team_member['display_name'],
644 'email' => $team_member['email'],
645 'image' => $team_member['image'],
646 );
647 }
648 }
649
650 return $team_member_details;
651 }
652
653 /**
654 * Get category details for given category IDs.
655 *
656 * @param array|int[] $category_ids
657 *
658 * @return array
659 */
660 private function category_details( $category_ids ): array {
661 $category_details = array();
662 foreach ( $category_ids as $category_id ) {
663 $category = get_term( $category_id, ( new Category() )->get_name() );
664
665 if ( $category ) {
666 $category = $category->to_array();
667 $category_details[] = array(
668 'id' => $category['term_id'],
669 'name' => $category['name'],
670 );
671 }
672 }
673
674 return $category_details;
675 }
676 }
677