PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.0
Booktics – Appointment Booking Calendar for Service Businesses v1.0.0
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 1.0.4 1.0.5 1.0.6 1.0.7 All 27 releases
booktics / core / service / controllers / service-controller.php

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

645 lines 22.1 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
279 if ( is_wp_error( $data ) ) {
280 return $this->error( $data->get_error_message() );
281 }
282
283 $service = Service_Model::create( $data );
284
285 do_action( 'booktics_service_created', $service, $request );
286
287 if ( is_wp_error( $service ) ) {
288 return $this->error( $service->get_error_message() );
289 }
290 $service = $service->to_array();
291 $service['shortcode'] = '[booktics-service-view id="' . $service['id'] . '"]';
292 $service['category_details'] = array();
293 $service['team_member_details'] = array();
294 $service = apply_filters( 'booktics_service_format', $service );
295
296 return $this->response( $service, __( 'Successfully created service', 'booktics' ) );
297 }
298
299 /**
300 * Check if a given request has access to create items.
301 *
302 * @param $request
303 *
304 * @return WP_Error
305 */
306 public function create_item_permissions_check( $request ): bool {
307 return true;
308 }
309
310 /**
311 * Update one item from the collection.
312 *
313 * @param $request
314 *
315 * @return WP_HTTP_Response
316 * @throws Exception
317 */
318 public function update_item( $request ) {
319 $id = (int) $request->get_param( 'id' );
320 $data = $this->prepare_item_for_database( $request );
321
322 if ( is_wp_error( $data ) ) {
323 return $this->error( $data->get_error_message() );
324 }
325
326 $service = Service_Model::find( $id );
327
328 if ( ! $service ) {
329 return $this->error( __( 'Service not found', 'booktics' ), 404 );
330 }
331
332 $result = $service->update( $data );
333
334 if ( is_wp_error( $result ) ) {
335 return $this->error( $result->get_error_message() );
336 }
337
338 if ( ! empty( $data['team_member'] ) && is_array( $data['team_member'] ) ) {
339 foreach ( $data['team_member'] as $team_member_id ) {
340 $team_member_model = ( new Team_Member_Model( $team_member_id ) );
341 $team_member = $team_member_model->find( $team_member_id );
342 $team_member_services = $team_member->services == '' ? array() : $team_member->services;
343
344 if ( ! in_array( (int) $id, $team_member_services ) ) {
345 $team_member_services[] = (int) $id;
346 if ( $team_member ) {
347 $team_member->update(
348 array(
349 'services' => $team_member_services,
350 )
351 );
352 }
353 }
354 }
355 }
356
357 $input_data = json_decode( $request->get_body(), true );
358 if ( isset( $input_data['schedule'] ) || isset( $input_data['custom'] ) || isset( $input_data['holiday'] ) ) {
359 $service_schedule = Schedule_Manager::make( $input_data );
360 $service_schedule->with_service_id( $request['id'] );
361 $service_schedule->save();
362 }
363
364 do_action( 'booktics_service_updated', $service, $request );
365
366 $response = Service_Model::find( $id )->to_array();
367 $response['shortcode'] = '[booktics-service-view id="' . $response['id'] . '"]';
368 $response['team_member_details'] = $this->team_member_details( $response['team_member'] );
369 if ( ! empty( $response['categories'] ) ) {
370 $category_ids = is_array( $response['categories'] ) ? $response['categories'] : array( $response['categories'] );
371 $response['category_details'] = $this->category_details( $category_ids );
372 }
373 $response = apply_filters( 'booktics_service_format', $response );
374
375 return $this->response( $response, __( 'Successfully updated service', 'booktics' ) );
376 }
377
378 /**
379 * Check if a given request has access to update a specific item.
380 *
381 * @param $request
382 *
383 * @return WP_Error
384 */
385 public function update_item_permissions_check( $request ) {
386 return true;
387 }
388
389 /**
390 * Delete one item from the collection.
391 *
392 * @param $request
393 *
394 * @return WP_HTTP_Response
395 */
396 public function delete_item( $request ) {
397 $id = intval( $request['id'] );
398
399 $service = Service_Model::find( $id );
400
401 if ( ! $service ) {
402 return $this->error( __( 'Service not found', 'booktics' ), 404 );
403 }
404
405 $deleted = $service->delete();
406
407 if ( is_wp_error( $deleted ) ) {
408 return $this->error( $deleted->get_error_message() );
409 }
410
411 return $this->response( (array) $service, __( 'Successfully deleted service', 'booktics' ) );
412 }
413
414 /**
415 * Check if a given request has access to delete a specific item.
416 *
417 * @param $request
418 *
419 * @return WP_Error
420 */
421 public function delete_item_permissions_check( $request ) {
422 return current_user_can( 'manage_options' );
423 }
424
425 /**
426 * Delete a collection of items
427 *
428 * @param $request
429 *
430 * @return WP_HTTP_Response
431 */
432 public function delete_items( $request ) {
433 $ids = $request['ids'];
434
435 if ( ! is_array( $ids ) ) {
436 return $this->error( __( 'Ids should be an array of items ids', 'booktics' ) );
437 }
438
439 $count = 0;
440 $total = count( $ids );
441
442 foreach ( $ids as $id ) {
443 $service = Service_Model::find( $id );
444
445 if ( $service ) {
446 $service->delete();
447 ++$count;
448 }
449 }
450
451 if ( $count === 0 ) {
452 return $this->error( __( 'No item deleted.', 'booktics' ) );
453 }
454
455 $message = sprintf( 'Deleted %d items of %d', $count, $total );
456
457 return $this->response( array(), $message );
458 }
459
460 /**
461 * Check if a given request has access to delete a collection of items.
462 *
463 * @param $request
464 *
465 * @return WP_Error
466 */
467 public function delete_items_permissions_check( $request ) {
468 return current_user_can( 'manage_options' );
469 }
470
471 /**
472 * Prepare the item for create or update operation.
473 *
474 * @param $request
475 *
476 * @return WP_Error
477 */
478 public function prepare_item_for_database( $request ) {
479 $data = json_decode( $request->get_body(), true );
480 $validate = booktics_validate(
481 $data, array(
482 'title' => array(
483 'required',
484 ),
485 )
486 );
487
488 if ( is_wp_error( $validate ) ) {
489 return $validate;
490 }
491
492 $data['title'] = ! empty( $data['title'] ) ? sanitize_text_field( $data['title'] ) : '';
493 $data['description'] = ! empty( $data['description'] ) ? sanitize_text_field( $data['description'] ) : '';
494 $data['content'] = ! empty( $data['content'] ) ? sanitize_text_field( $data['content'] ) : '';
495 $data['link'] = ! empty( $data['link'] ) ? sanitize_text_field( $data['link'] ) : '';
496 $data['image'] = ! empty( $data['image'] ) ? esc_url_raw( $data['image'] ) : '';
497 $data['image_id'] = ! empty( $data['image_id'] ) ? esc_url_raw( $data['image_id'] ) : '';
498 $data['interval_time'] = ! empty( $data['interval_time'] ) ? sanitize_text_field( $data['interval_time'] ) : '';
499 $data['before_buffer_time'] = ! empty( $data['before_buffer_time'] ) ? sanitize_text_field( $data['before_buffer_time'] ) : '';
500 $data['status'] = ! empty( $data['status'] ) ? sanitize_text_field( $data['status'] ) : 'deactive';
501 $data['team_member'] = empty( $data['team_member'] ) ? array() : array_unique( $data['team_member'] );
502 $data['categories'] = empty( $data['categories'] ) ? array() : array_unique( $data['categories'] );
503 $sanitized_durations = array();
504 if ( ! empty( $data['additional_durations'] ) ) {
505 foreach ( $data['additional_durations'] as $duration ) {
506 if ( is_array( $duration ) ) {
507 $sanitized_durations[] = array(
508 'id' => ! empty( $duration['id'] ) ? sanitize_text_field( $duration['id'] ) : '',
509 'name' => ! empty( $duration['name'] ) ? sanitize_text_field( $duration['name'] ) : '',
510 'duration_time' => ! empty( $duration['duration_time'] ) ? sanitize_text_field( $duration['duration_time'] ) : '',
511 'duration_unit' => ! empty( $duration['duration_unit'] ) ? sanitize_text_field( $duration['duration_unit'] ) : '',
512 'charge_amount' => ! empty( $duration['charge_amount'] ) ? (float) number_format( (float) $duration['charge_amount'], 4, '.', '' ) : '0.0000',
513 'deposit_amount' => ! empty( $duration['deposit_amount'] ) ? (float) number_format( (float) $duration['deposit_amount'], 4, '.', '' ) : '0.0000',
514 );
515 }
516 }
517 }
518 $data['additional_durations'] = $sanitized_durations;
519 $data = apply_filters( 'booktics_prepare_service_custom_fields', $data );
520 $image_url = $request->get_param( 'image' );
521 if ( $image_url ) {
522 $data['image'] = esc_url_raw( $image_url );
523 }
524
525 return $data;
526 }
527
528 /**
529 * Clone service from the record.
530 *
531 * @param $request
532 *
533 * @return WP_HTTP_Response
534 * @throws Exception
535 */
536 public function clone_item( $request ) {
537 $id = intval( $request['id'] );
538
539 $service = Service_Model::find( $id );
540
541 if ( ! $service ) {
542 return $this->error( __( 'Service not found', 'booktics' ), 404 );
543 }
544
545 $cloned = Service_Model::create(
546 array(
547 'title' => $service->title . __( ' Copy', 'booktics' ),
548 'description' => $service->description,
549 'content' => $service->content,
550 'image' => $service->image,
551 'image_id' => $service->image_id,
552 'categories' => $service->categories,
553 'interval_time' => $service->interval_time,
554 'before_buffer_time' => $service->before_buffer_time,
555 'after_buffer_time' => $service->after_buffer_time,
556 'team_member' => $service->team_member,
557 'show_end_time' => $service->show_end_time,
558 'additional_durations' => $service->additional_durations,
559 'enable_custom_holiday' => $service->enable_custom_holiday,
560 'enable_custom_schedule' => $service->enable_custom_schedule,
561 'enable_additional_service_duration' => $service->enable_additional_service_duration,
562 'custom_field' => $service->custom_field,
563 'extra_services' => $service->extra_services,
564 )
565 );
566
567 if ( is_wp_error( $cloned ) ) {
568 return $this->error( $cloned->get_error_message() );
569 }
570
571 $schedule_record = ( new Schedule_Record() )
572 ->get_schedules( $id, 'service' );
573 $schedule_data['schedule'] = $schedule_record['schedule'];
574 $schedule_data['custom'] = $schedule_record['custom'];
575 $schedule_data['holiday'] = $schedule_record['holiday'];
576
577 $service_schedule = Schedule_Manager::make( $schedule_data );
578 $service_schedule->with_service_id( $cloned->id );
579 $service_schedule->save();
580
581 $team_member_details = $this->team_member_details( $service->team_member );
582 $cloned = $cloned->to_array();
583 $cloned['team_member_details'] = $team_member_details;
584
585 $clone_schedule_record = ( new Schedule_Record() )
586 ->get_schedules( $cloned['id'], 'service' );
587 $cloned['schedule'] = empty( $clone_schedule_record['schedule'] ) ? (object) array()
588 : $clone_schedule_record['schedule'];
589 $cloned['custom'] = $clone_schedule_record['custom'];
590 $cloned['holiday'] = $clone_schedule_record['holiday'];
591 $cloned = apply_filters( 'booktics_service_format', $cloned );
592
593 return $this->response( $cloned, __( 'Successfully cloned service', 'booktics' ) );
594 }
595
596 /**
597 * Map team member details
598 *
599 * @param $team_member_ids
600 *
601 * @return array
602 */
603 private function team_member_details( $team_member_ids ): array {
604 $team_member_details = array();
605 foreach ( $team_member_ids as $team_member_id ) {
606 $team_member = ( new Team_Member_Model() )->find( $team_member_id );
607 if ( $team_member ) {
608 $team_member = $team_member->to_array();
609 $team_member_details[] = array(
610 'id' => $team_member['id'],
611 'display_name' => $team_member['display_name'],
612 'email' => $team_member['email'],
613 'image' => $team_member['image'],
614 );
615 }
616 }
617
618 return $team_member_details;
619 }
620
621 /**
622 * Get category details for given category IDs.
623 *
624 * @param array|int[] $category_ids
625 *
626 * @return array
627 */
628 private function category_details( $category_ids ): array {
629 $category_details = array();
630 foreach ( $category_ids as $category_id ) {
631 $category = get_term( $category_id, ( new Category() )->get_name() );
632
633 if ( $category ) {
634 $category = $category->to_array();
635 $category_details[] = array(
636 'id' => $category['term_id'],
637 'name' => $category['name'],
638 );
639 }
640 }
641
642 return $category_details;
643 }
644 }
645