Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like WPInv_REST_Invoice_Controller often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use WPInv_REST_Invoice_Controller, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
20 | class WPInv_REST_Invoice_Controller extends WP_REST_Posts_Controller { |
||
21 | |||
22 | /** |
||
23 | * Post type. |
||
24 | * |
||
25 | * @var string |
||
26 | */ |
||
27 | protected $post_type = 'wpi_invoice'; |
||
28 | |||
29 | /** |
||
30 | * Cached results of get_item_schema. |
||
31 | * |
||
32 | * @since 1.0.13 |
||
33 | * @var array |
||
34 | */ |
||
35 | protected $schema; |
||
36 | |||
37 | /** |
||
38 | * Constructor. |
||
39 | * |
||
40 | * @since 1.0.13 |
||
41 | * |
||
42 | * @param string $namespace Api Namespace |
||
43 | */ |
||
44 | public function __construct( $namespace ) { |
||
45 | |||
46 | // Set api namespace... |
||
47 | $this->namespace = $namespace; |
||
48 | |||
49 | // ... and the rest base |
||
50 | $this->rest_base = 'invoices'; |
||
51 | |||
52 | } |
||
53 | |||
54 | /** |
||
55 | * Checks if a given request has access to read invoices. |
||
56 | * |
||
57 | * |
||
58 | * @since 1.0.13 |
||
59 | * |
||
60 | * @param WP_REST_Request $request Full details about the request. |
||
61 | * @return true|WP_Error True if the request has read access, WP_Error object otherwise. |
||
62 | */ |
||
63 | public function get_items_permissions_check( $request ) { |
||
64 | |||
65 | $post_type = get_post_type_object( $this->post_type ); |
||
66 | |||
67 | if ( 'edit' === $request['context'] && ! current_user_can( $post_type->cap->edit_posts ) ) { |
||
68 | return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit invoices.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) ); |
||
69 | } |
||
70 | |||
71 | // Read checks will be evaluated on a per invoice basis |
||
72 | |||
73 | return true; |
||
74 | |||
75 | } |
||
76 | |||
77 | /** |
||
78 | * Retrieves a collection of invoices. |
||
79 | * |
||
80 | * @since 1.0.13 |
||
81 | * |
||
82 | * @param WP_REST_Request $request Full details about the request. |
||
83 | * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
||
84 | */ |
||
85 | public function get_items( $request ) { |
||
86 | |||
87 | // Retrieve the list of registered invoice query parameters. |
||
88 | $registered = $this->get_collection_params(); |
||
89 | |||
90 | $args = array(); |
||
91 | |||
92 | foreach( array_keys( $registered ) as $key ) { |
||
93 | |||
94 | if( isset( $request[ $key] ) ) { |
||
95 | $args[ $key ] = $request[ $key]; |
||
96 | } |
||
97 | |||
98 | } |
||
99 | |||
100 | /** |
||
101 | * Filters the wpinv_get_invoices arguments for invoices requests. |
||
102 | * |
||
103 | * |
||
104 | * @since 1.0.13 |
||
105 | * |
||
106 | * |
||
107 | * @param array $args Key value array of query var to query value. |
||
108 | * @param WP_REST_Request $request The request used. |
||
109 | */ |
||
110 | $args = apply_filters( "wpinv_rest_get_invoices_arguments", $args, $request, $this ); |
||
111 | |||
112 | // Special args |
||
113 | $args[ 'return' ] = 'objects'; |
||
114 | $args[ 'paginate' ] = true; |
||
115 | |||
116 | // Run the query. |
||
117 | $query = wpinv_get_invoices( $args ); |
||
118 | |||
119 | // Prepare the retrieved invoices |
||
120 | $invoices = array(); |
||
121 | foreach( $query->invoices as $invoice ) { |
||
122 | |||
123 | if ( ! $this->check_read_permission( $invoice ) ) { |
||
124 | continue; |
||
125 | } |
||
126 | |||
127 | $data = $this->prepare_item_for_response( $invoice, $request ); |
||
128 | $invoices[] = $this->prepare_response_for_collection( $data ); |
||
129 | |||
130 | } |
||
131 | |||
132 | // Prepare the response. |
||
133 | $response = rest_ensure_response( $invoices ); |
||
134 | $response->header( 'X-WP-Total', (int) $query->total ); |
||
135 | $response->header( 'X-WP-TotalPages', (int) $query->max_num_pages ); |
||
136 | |||
137 | /** |
||
138 | * Filters the responses for invoices requests. |
||
139 | * |
||
140 | * |
||
141 | * @since 1.0.13 |
||
142 | * |
||
143 | * |
||
144 | * @param arrWP_REST_Response $response Response object. |
||
145 | * @param WP_REST_Request $request The request used. |
||
146 | * @param array $args Array of args used to retrieve the invoices |
||
147 | */ |
||
148 | $response = apply_filters( "wpinv_rest_invoices_response", $response, $request, $args ); |
||
149 | |||
150 | return rest_ensure_response( $response ); |
||
151 | |||
152 | } |
||
153 | |||
154 | /** |
||
155 | * Get the post, if the ID is valid. |
||
156 | * |
||
157 | * @since 1.0.13 |
||
158 | * |
||
159 | * @param int $invoice_id Supplied ID. |
||
160 | * @return WPInv_Invoice|WP_Error Invoice object if ID is valid, WP_Error otherwise. |
||
161 | */ |
||
162 | protected function get_post( $invoice_id ) { |
||
177 | |||
178 | } |
||
179 | |||
180 | /** |
||
181 | * Checks if a given request has access to read an invoice. |
||
182 | * |
||
183 | * @since 1.0.13 |
||
184 | * |
||
185 | * @param WP_REST_Request $request Full details about the request. |
||
186 | * @return bool|WP_Error True if the request has read access for the invoice, WP_Error object otherwise. |
||
187 | */ |
||
188 | public function get_item_permissions_check( $request ) { |
||
189 | |||
190 | // Retrieve the invoice object. |
||
191 | $invoice = $this->get_post( $request['id'] ); |
||
192 | |||
193 | // Ensure it is valid. |
||
194 | if ( is_wp_error( $invoice ) ) { |
||
195 | return $invoice; |
||
|
|||
196 | } |
||
197 | |||
198 | if ( $invoice ) { |
||
199 | return $this->check_read_permission( $invoice ); |
||
200 | } |
||
201 | |||
202 | return true; |
||
203 | } |
||
204 | |||
205 | /** |
||
206 | * Checks if an invoice can be read. |
||
207 | * |
||
208 | * An invoice can be read by site admins and owners of the invoice |
||
209 | * |
||
210 | * |
||
211 | * @since 1.0.13 |
||
212 | * |
||
213 | * @param WPInv_Invoice $invoice WPInv_Invoice object. |
||
214 | * @return bool Whether the post can be read. |
||
215 | */ |
||
216 | public function check_read_permission( $invoice ) { |
||
217 | return wpinv_user_can_view_invoice( $invoice->ID ); |
||
218 | } |
||
219 | |||
220 | /** |
||
221 | * Retrieves a single invoice. |
||
222 | * |
||
223 | * @since 1.0.13 |
||
224 | * |
||
225 | * @param WP_REST_Request $request Full details about the request. |
||
226 | * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
||
227 | */ |
||
228 | public function get_item( $request ) { |
||
229 | |||
230 | // Fetch the invoice. |
||
231 | $invoice = $this->get_post( $request['id'] ); |
||
232 | |||
233 | // Abort early if it does not exist |
||
234 | if ( is_wp_error( $invoice ) ) { |
||
235 | return $invoice; |
||
236 | } |
||
237 | |||
238 | // Prepare the response |
||
239 | $response = $this->prepare_item_for_response( $invoice, $request ); |
||
240 | $response->link_header( 'alternate', esc_url( $invoice->get_view_url() ), array( 'type' => 'text/html' ) ); |
||
241 | |||
242 | /** |
||
243 | * Filters the responses for single invoice requests. |
||
244 | * |
||
245 | * |
||
246 | * @since 1.0.13 |
||
247 | * @var WP_HTTP_Response |
||
248 | * |
||
249 | * @param WP_HTTP_Response $response Response. |
||
250 | * @param WP_REST_Request $request The request used. |
||
251 | */ |
||
252 | $response = apply_filters( "wpinv_rest_get_invoice_response", $response, $request ); |
||
253 | |||
254 | return rest_ensure_response( $response ); |
||
255 | |||
256 | } |
||
257 | |||
258 | /** |
||
259 | * Checks if a given request has access to create an invoice. |
||
260 | * |
||
261 | * @since 1.0.13 |
||
262 | * |
||
263 | * @param WP_REST_Request $request Full details about the request. |
||
264 | * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. |
||
265 | */ |
||
266 | public function create_item_permissions_check( $request ) { |
||
267 | |||
268 | if ( ! empty( $request['id'] ) ) { |
||
269 | return new WP_Error( 'rest_invoice_exists', __( 'Cannot create existing invoice.', 'invoicing' ), array( 'status' => 400 ) ); |
||
270 | } |
||
271 | |||
272 | $post_type = get_post_type_object( $this->post_type ); |
||
273 | |||
274 | if ( ! current_user_can( $post_type->cap->create_posts ) ) { |
||
275 | return new WP_Error( |
||
276 | 'rest_cannot_create', |
||
277 | __( 'Sorry, you are not allowed to create invoices as this user.', 'invoicing' ), |
||
278 | array( |
||
279 | 'status' => rest_authorization_required_code(), |
||
280 | ) |
||
281 | ); |
||
282 | } |
||
283 | |||
284 | return true; |
||
285 | } |
||
286 | |||
287 | /** |
||
288 | * Creates a single invoice. |
||
289 | * |
||
290 | * @since 1.0.13 |
||
291 | * |
||
292 | * @param WP_REST_Request $request Full details about the request. |
||
293 | * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
||
294 | */ |
||
295 | public function create_item( $request ) { |
||
296 | |||
297 | if ( ! empty( $request['id'] ) ) { |
||
298 | return new WP_Error( 'rest_invoice_exists', __( 'Cannot create existing invoice.', 'invoicing' ), array( 'status' => 400 ) ); |
||
299 | } |
||
300 | |||
301 | $request->set_param( 'context', 'edit' ); |
||
302 | |||
303 | // Prepare the updated data. |
||
304 | $invoice_data = $this->prepare_item_for_database( $request ); |
||
305 | |||
306 | if ( is_wp_error( $invoice_data ) ) { |
||
307 | return $invoice_data; |
||
308 | } |
||
309 | |||
310 | // Try creating the invoice |
||
311 | $invoice = wpinv_insert_invoice( $invoice_data, true ); |
||
312 | |||
313 | if ( is_wp_error( $invoice ) ) { |
||
314 | return $invoice; |
||
315 | } |
||
316 | |||
317 | // Prepare the response |
||
318 | $response = $this->prepare_item_for_response( $invoice, $request ); |
||
319 | |||
320 | /** |
||
321 | * Fires after a single invoice is created or updated via the REST API. |
||
322 | * |
||
323 | * @since 1.0.13 |
||
324 | * |
||
325 | * @param WPinv_Invoice $invoice Inserted or updated invoice object. |
||
326 | * @param WP_REST_Request $request Request object. |
||
327 | * @param bool $creating True when creating a post, false when updating. |
||
328 | */ |
||
329 | do_action( "wpinv_rest_insert_invoice", $invoice, $request, true ); |
||
330 | |||
331 | /** |
||
332 | * Filters the responses for creating single invoice requests. |
||
333 | * |
||
334 | * |
||
335 | * @since 1.0.13 |
||
336 | * |
||
337 | * |
||
338 | * @param array $invoice_data Invoice properties. |
||
339 | * @param WP_REST_Request $request The request used. |
||
340 | */ |
||
341 | $response = apply_filters( "wpinv_rest_create_invoice_response", $response, $request ); |
||
342 | |||
343 | return rest_ensure_response( $response ); |
||
344 | } |
||
345 | |||
346 | /** |
||
347 | * Checks if a given request has access to update an invoice. |
||
348 | * |
||
349 | * @since 1.0.13 |
||
350 | * |
||
351 | * @param WP_REST_Request $request Full details about the request. |
||
352 | * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. |
||
353 | */ |
||
354 | public function update_item_permissions_check( $request ) { |
||
355 | |||
356 | // Retrieve the invoice. |
||
357 | $invoice = $this->get_post( $request['id'] ); |
||
358 | if ( is_wp_error( $invoice ) ) { |
||
359 | return $invoice; |
||
360 | } |
||
361 | |||
362 | $post_type = get_post_type_object( $this->post_type ); |
||
363 | |||
364 | if ( ! current_user_can( $post_type->cap->edit_post, $invoice->ID ) ) { |
||
365 | return new WP_Error( |
||
366 | 'rest_cannot_edit', |
||
367 | __( 'Sorry, you are not allowed to update this invoice.', 'invoicing' ), |
||
368 | array( |
||
369 | 'status' => rest_authorization_required_code(), |
||
370 | ) |
||
371 | ); |
||
372 | } |
||
373 | |||
374 | return true; |
||
375 | } |
||
376 | |||
377 | /** |
||
378 | * Updates a single invoice. |
||
379 | * |
||
380 | * @since 1.0.13 |
||
381 | * |
||
382 | * @param WP_REST_Request $request Full details about the request. |
||
383 | * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
||
384 | */ |
||
385 | public function update_item( $request ) { |
||
386 | |||
387 | // Ensure the invoice exists. |
||
388 | $valid_check = $this->get_post( $request['id'] ); |
||
389 | |||
390 | // Abort early if it does not exist |
||
391 | if ( is_wp_error( $valid_check ) ) { |
||
392 | return $valid_check; |
||
393 | } |
||
394 | |||
395 | $request->set_param( 'context', 'edit' ); |
||
396 | |||
397 | // Prepare the updated data. |
||
398 | $data_to_update = $this->prepare_item_for_database( $request ); |
||
399 | |||
400 | if ( is_wp_error( $data_to_update ) ) { |
||
401 | return $data_to_update; |
||
402 | } |
||
403 | |||
404 | // Abort if no invoice data is provided |
||
405 | if( empty( $data_to_update ) ) { |
||
406 | return new WP_Error( 'missing_data', __( 'An update request cannot be empty.', 'invoicing' ) ); |
||
407 | } |
||
408 | |||
409 | // Include the invoice ID |
||
410 | $data_to_update['ID'] = $request['id']; |
||
411 | |||
412 | // Update the invoice |
||
413 | $updated_invoice = wpinv_update_invoice( $data_to_update, true ); |
||
414 | |||
415 | // Incase the update operation failed... |
||
416 | if ( is_wp_error( $updated_invoice ) ) { |
||
417 | return $updated_invoice; |
||
418 | } |
||
419 | |||
420 | // Prepare the response |
||
421 | $response = $this->prepare_item_for_response( $updated_invoice, $request ); |
||
422 | |||
423 | /** This action is documented in includes/class-wpinv-rest-invoice-controller.php */ |
||
424 | do_action( "wpinv_rest_insert_invoice", $updated_invoice, $request, false ); |
||
425 | |||
426 | /** |
||
427 | * Filters the responses for updating single invoice requests. |
||
428 | * |
||
429 | * |
||
430 | * @since 1.0.13 |
||
431 | * |
||
432 | * |
||
433 | * @param array $invoice_data Invoice properties. |
||
434 | * @param WP_REST_Request $request The request used. |
||
435 | */ |
||
436 | $response = apply_filters( "wpinv_rest_update_invoice_response", $response, $request ); |
||
437 | |||
438 | return rest_ensure_response( $response ); |
||
439 | } |
||
440 | |||
441 | /** |
||
442 | * Checks if a given request has access to delete an invoice. |
||
443 | * |
||
444 | * @since 1.0.13 |
||
445 | * |
||
446 | * @param WP_REST_Request $request Full details about the request. |
||
447 | * @return true|WP_Error True if the request has access to delete the invoice, WP_Error object otherwise. |
||
448 | */ |
||
449 | public function delete_item_permissions_check( $request ) { |
||
450 | |||
451 | // Retrieve the invoice. |
||
452 | $invoice = $this->get_post( $request['id'] ); |
||
453 | if ( is_wp_error( $invoice ) ) { |
||
454 | return $invoice; |
||
455 | } |
||
456 | |||
457 | // Ensure the current user can delete invoices |
||
458 | if ( wpinv_current_user_can_manage_invoicing() || current_user_can( 'delete_invoices', $request['id'] ) ) { |
||
459 | return new WP_Error( |
||
460 | 'rest_cannot_delete', |
||
461 | __( 'Sorry, you are not allowed to delete this invoice.', 'invoicing' ), |
||
462 | array( |
||
463 | 'status' => rest_authorization_required_code(), |
||
464 | ) |
||
465 | ); |
||
466 | } |
||
467 | |||
468 | return true; |
||
469 | } |
||
470 | |||
471 | /** |
||
472 | * Deletes a single invoice. |
||
473 | * |
||
474 | * @since 1.0.13 |
||
475 | * |
||
476 | * @param WP_REST_Request $request Full details about the request. |
||
477 | * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
||
478 | */ |
||
479 | public function delete_item( $request ) { |
||
480 | |||
481 | // Retrieve the invoice. |
||
482 | $invoice = $this->get_post( $request['id'] ); |
||
483 | if ( is_wp_error( $invoice ) ) { |
||
484 | return $invoice; |
||
485 | } |
||
486 | |||
487 | $request->set_param( 'context', 'edit' ); |
||
488 | |||
489 | // Prepare the invoice id |
||
490 | $id = $invoice->ID; |
||
491 | |||
492 | // Prepare the response |
||
493 | $response = $this->prepare_item_for_response( $invoice, $request ); |
||
494 | |||
495 | // Check if the user wants to bypass the trash... |
||
496 | $force_delete = (bool) $request['force']; |
||
497 | |||
498 | // Try deleting the invoice. |
||
499 | $deleted = wp_delete_post( $id, $force_delete ); |
||
500 | |||
501 | // Abort early if we can't delete the invoice. |
||
502 | if ( ! $deleted ) { |
||
503 | return new WP_Error( 'rest_cannot_delete', __( 'The invoice cannot be deleted.', 'invoicing' ), array( 'status' => 500 ) ); |
||
504 | } |
||
505 | |||
506 | /** |
||
507 | * Fires immediately after a single invoice is deleted or trashed via the REST API. |
||
508 | * |
||
509 | * |
||
510 | * @since 1.0.13 |
||
511 | * |
||
512 | * @param WPInv_Invoice $invoice The deleted or trashed invoice. |
||
513 | * @param WP_REST_Request $request The request sent to the API. |
||
514 | */ |
||
515 | do_action( "wpinv_rest_delete_invoice", $invoice, $request ); |
||
516 | |||
517 | return $response; |
||
518 | |||
519 | } |
||
520 | |||
521 | |||
522 | /** |
||
523 | * Retrieves the query params for the invoices collection. |
||
524 | * |
||
525 | * @since 1.0.13 |
||
526 | * |
||
527 | * @return array Collection parameters. |
||
528 | */ |
||
529 | public function get_collection_params() { |
||
530 | |||
531 | $query_params = array( |
||
532 | |||
533 | // Invoice status. |
||
534 | 'status' => array( |
||
535 | 'default' => 'publish', |
||
536 | 'description' => __( 'Limit result set to invoices assigned one or more statuses.', 'invoicing' ), |
||
537 | 'type' => 'array', |
||
538 | 'items' => array( |
||
539 | 'enum' => array_keys( wpinv_get_invoice_statuses( true, true ) ), |
||
540 | 'type' => 'string', |
||
541 | ), |
||
542 | 'sanitize_callback' => array( $this, 'sanitize_post_statuses' ), |
||
543 | ), |
||
544 | |||
545 | // User. |
||
546 | 'user' => array( |
||
547 | 'description' => __( 'Limit result set to invoices for a specif user.', 'invoicing' ), |
||
548 | 'type' => 'integer', |
||
549 | ), |
||
550 | |||
551 | // Number of results per page |
||
552 | 'limit' => array( |
||
553 | 'description' => __( 'Number of invoices to fetch.', 'invoicing' ), |
||
554 | 'type' => 'integer', |
||
555 | 'default' => (int) get_option( 'posts_per_page' ), |
||
556 | ), |
||
557 | |||
558 | // Pagination |
||
559 | 'page' => array( |
||
560 | 'description' => __( 'Current page to fetch.', 'invoicing' ), |
||
561 | 'type' => 'integer', |
||
562 | 'default' => 1, |
||
563 | ), |
||
564 | |||
565 | // Exclude certain invoices |
||
566 | 'exclude' => array( |
||
567 | 'description' => __( 'Ensure result set excludes specific IDs.', 'invoicing' ), |
||
568 | 'type' => 'array', |
||
569 | 'items' => array( |
||
570 | 'type' => 'integer', |
||
571 | ), |
||
572 | 'default' => array(), |
||
573 | ), |
||
574 | |||
575 | // Order invoices by |
||
576 | 'orderby' => array( |
||
577 | 'description' => __( 'Sort invoices by object attribute.', 'invoicing' ), |
||
578 | 'type' => 'string', |
||
579 | 'default' => 'date', |
||
580 | 'enum' => array( |
||
581 | 'author', |
||
582 | 'date', |
||
583 | 'id', |
||
584 | 'modified', |
||
585 | 'title' |
||
586 | ), |
||
587 | ), |
||
588 | |||
589 | // How to order |
||
590 | 'order' => array( |
||
591 | 'description' => __( 'Order sort attribute ascending or descending.', 'invoicing' ), |
||
592 | 'type' => 'string', |
||
593 | 'default' => 'DESC', |
||
594 | 'enum' => array( 'ASC', 'DESC' ), |
||
595 | ), |
||
596 | ); |
||
597 | |||
598 | /** |
||
599 | * Filter collection parameters for the invoices controller. |
||
600 | * |
||
601 | * |
||
602 | * @since 1.0.13 |
||
603 | * |
||
604 | * @param array $query_params JSON Schema-formatted collection parameters. |
||
605 | */ |
||
606 | return apply_filters( "wpinv_rest_invoices_collection_params", $query_params ); |
||
607 | } |
||
608 | |||
609 | /** |
||
610 | * Checks if a given post type can be viewed or managed. |
||
611 | * |
||
612 | * @since 1.0.13 |
||
613 | * |
||
614 | * @param object|string $post_type Post type name or object. |
||
615 | * @return bool Whether the post type is allowed in REST. |
||
616 | */ |
||
617 | protected function check_is_post_type_allowed( $post_type ) { |
||
618 | return true; |
||
619 | } |
||
620 | |||
621 | /** |
||
622 | * Prepares a single invoice for create or update. |
||
623 | * |
||
624 | * @since 1.0.13 |
||
625 | * |
||
626 | * @param WP_REST_Request $request Request object. |
||
627 | * @return array|WP_Error Invoice Properties or WP_Error. |
||
628 | */ |
||
629 | protected function prepare_item_for_database( $request ) { |
||
630 | $prepared_invoice = new stdClass(); |
||
631 | |||
632 | // Post ID. |
||
633 | if ( isset( $request['id'] ) ) { |
||
634 | $existing_invoice = $this->get_post( $request['id'] ); |
||
635 | if ( is_wp_error( $existing_invoice ) ) { |
||
636 | return $existing_invoice; |
||
637 | } |
||
638 | |||
639 | $prepared_invoice->ID = $existing_invoice->ID; |
||
640 | $prepared_invoice->invoice_id = $existing_invoice->ID; |
||
641 | } |
||
642 | |||
643 | $schema = $this->get_item_schema(); |
||
644 | |||
645 | // Invoice owner. |
||
646 | if ( ! empty( $schema['properties']['user_id'] ) && isset( $request['user_id'] ) ) { |
||
647 | $prepared_invoice->user_id = (int) $request['user_id']; |
||
648 | } |
||
649 | |||
650 | // Cart details. |
||
651 | if ( ! empty( $schema['properties']['cart_details'] ) && isset( $request['cart_details'] ) ) { |
||
652 | $prepared_invoice->cart_details = (array) $request['cart_details']; |
||
653 | } |
||
654 | |||
655 | // Invoice status. |
||
656 | if ( ! empty( $schema['properties']['status'] ) && isset( $request['status'] ) ) { |
||
657 | |||
658 | if ( in_array( $request['status'], array_keys( wpinv_get_invoice_statuses( true, true ) ), true ) ) { |
||
659 | $prepared_invoice->status = $request['status']; |
||
660 | } |
||
661 | |||
662 | } |
||
663 | |||
664 | // User info |
||
665 | if ( ! empty( $schema['properties']['user_info'] ) && isset( $request['user_info'] ) ) { |
||
666 | $prepared_invoice->user_info = array(); |
||
667 | $user_info = (array) $request['user_info']; |
||
668 | |||
669 | foreach( $user_info as $prop => $value ) { |
||
670 | |||
671 | if ( ! empty( $schema['properties']['user_info']['properties'][$prop] ) ) { |
||
672 | |||
673 | $prepared_invoice->user_info[$prop] = $value; |
||
674 | |||
675 | } |
||
676 | |||
677 | } |
||
678 | |||
679 | } |
||
680 | |||
681 | // IP |
||
682 | if ( ! empty( $schema['properties']['ip'] ) && isset( $request['ip'] ) ) { |
||
683 | $prepared_invoice->ip = $request['ip']; |
||
684 | } |
||
685 | |||
686 | // Payment details |
||
687 | $prepared_invoice->payment_details = array(); |
||
688 | |||
689 | if ( ! empty( $schema['properties']['gateway'] ) && isset( $request['gateway'] ) ) { |
||
690 | $prepared_invoice->payment_details['gateway'] = $request['gateway']; |
||
691 | } |
||
692 | |||
693 | if ( ! empty( $schema['properties']['gateway_title'] ) && isset( $request['gateway_title'] ) ) { |
||
694 | $prepared_invoice->payment_details['gateway_title'] = $request['gateway_title']; |
||
695 | } |
||
696 | |||
697 | if ( ! empty( $schema['properties']['currency'] ) && isset( $request['currency'] ) ) { |
||
698 | $prepared_invoice->payment_details['currency'] = $request['currency']; |
||
699 | } |
||
700 | |||
701 | if ( ! empty( $schema['properties']['transaction_id'] ) && isset( $request['transaction_id'] ) ) { |
||
702 | $prepared_invoice->payment_details['transaction_id'] = $request['transaction_id']; |
||
703 | } |
||
704 | |||
705 | // Dates |
||
706 | if ( ! empty( $schema['properties']['date'] ) && isset( $request['date'] ) ) { |
||
707 | $post_date = rest_get_date_with_gmt( $request['date'] ); |
||
708 | |||
709 | if ( ! empty( $post_date ) ) { |
||
710 | $prepared_invoice->post_date = $post_date[0]; |
||
711 | } |
||
712 | |||
713 | } |
||
714 | |||
715 | if ( ! empty( $schema['properties']['due_date'] ) && isset( $request['due_date'] ) ) { |
||
716 | $due_date = rest_get_date_with_gmt( $request['due_date'] ); |
||
717 | |||
718 | if ( ! empty( $due_date ) ) { |
||
719 | $prepared_invoice->due_date = $due_date[0]; |
||
720 | } |
||
721 | |||
722 | } |
||
723 | |||
724 | $invoice_data = (array) wp_unslash( $prepared_invoice ); |
||
725 | |||
726 | /** |
||
727 | * Filters an invoice before it is inserted via the REST API. |
||
728 | * |
||
729 | * @since 1.0.13 |
||
730 | * |
||
731 | * @param array $invoice_data An array of invoice data |
||
732 | * @param WP_REST_Request $request Request object. |
||
733 | */ |
||
734 | return apply_filters( "wpinv_rest_pre_insert_invoice", $invoice_data, $request ); |
||
735 | |||
736 | } |
||
737 | |||
738 | /** |
||
739 | * Prepares a single invoice output for response. |
||
740 | * |
||
741 | * @since 1.0.13 |
||
742 | * |
||
743 | * @param WPInv_Invoice $invoice Invoice object. |
||
744 | * @param WP_REST_Request $request Request object. |
||
745 | * @return WP_REST_Response Response object. |
||
746 | */ |
||
747 | public function prepare_item_for_response( $invoice, $request ) { |
||
748 | |||
749 | $GLOBALS['post'] = get_post( $invoice->ID ); |
||
750 | |||
751 | setup_postdata( $invoice->ID ); |
||
752 | |||
753 | // Fetch the fields to include in this response. |
||
754 | $fields = $this->get_fields_for_response( $request ); |
||
755 | |||
756 | // Base fields for every invoice. |
||
757 | $data = array(); |
||
758 | |||
759 | // Set up ID |
||
760 | if ( rest_is_field_included( 'id', $fields ) ) { |
||
761 | $data['id'] = $invoice->ID; |
||
762 | } |
||
763 | |||
764 | |||
765 | // Basic properties |
||
766 | $invoice_properties = array( |
||
767 | 'title', 'email', 'ip', |
||
768 | 'key', 'number', 'transaction_id', 'mode', |
||
769 | 'gateway', 'gateway_title', |
||
770 | 'total', 'discount', 'discount_code', |
||
771 | 'tax', 'fees_total', 'subtotal', 'currency', |
||
772 | 'status', 'status_nicename', 'post_type' |
||
773 | ); |
||
774 | |||
775 | foreach( $invoice_properties as $property ) { |
||
776 | |||
777 | if ( rest_is_field_included( $property, $fields ) ) { |
||
778 | $data[$property] = $invoice->get( $property ); |
||
779 | } |
||
780 | |||
781 | } |
||
782 | |||
783 | // Cart details |
||
784 | if ( rest_is_field_included( 'cart_details', $fields ) ) { |
||
785 | $data['cart_details'] = $invoice->get( 'cart_details' ); |
||
786 | } |
||
787 | |||
788 | //Dates |
||
789 | $invoice_properties = array( 'date', 'due_date', 'completed_date' ); |
||
790 | |||
791 | foreach( $invoice_properties as $property ) { |
||
792 | |||
793 | if ( rest_is_field_included( $property, $fields ) ) { |
||
794 | $data[$property] = $this->prepare_date_response( '0000-00-00 00:00:00', $invoice->get( $property ) ); |
||
795 | } |
||
796 | |||
797 | } |
||
798 | |||
799 | // User id |
||
800 | if ( rest_is_field_included( 'user_id', $fields ) ) { |
||
801 | $data['user_id'] = (int) $invoice->get( 'user_id' ); |
||
802 | } |
||
803 | |||
804 | // User info |
||
805 | $user_info = array( 'first_name', 'last_name', 'company', 'vat_number', 'vat_rate', 'address', 'city', 'country', 'state', 'zip', 'phone' ); |
||
806 | |||
807 | foreach( $user_info as $property ) { |
||
808 | |||
809 | if ( rest_is_field_included( "user_info.$property", $fields ) ) { |
||
810 | $data['user_info'][$property] = $invoice->get( $property ); |
||
811 | } |
||
812 | |||
813 | } |
||
814 | |||
815 | // Slug |
||
816 | if ( rest_is_field_included( 'slug', $fields ) ) { |
||
817 | $data['slug'] = $invoice->get( 'post_name' ); |
||
818 | } |
||
819 | |||
820 | // View invoice link |
||
821 | if ( rest_is_field_included( 'link', $fields ) ) { |
||
822 | $data['link'] = esc_url( $invoice->get_view_url() ); |
||
823 | } |
||
824 | |||
825 | |||
826 | $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; |
||
827 | $data = $this->add_additional_fields_to_object( $data, $request ); |
||
828 | $data = $this->filter_response_by_context( $data, $context ); |
||
829 | |||
830 | // Wrap the data in a response object. |
||
831 | $response = rest_ensure_response( $data ); |
||
832 | |||
833 | $links = $this->prepare_links( $invoice ); |
||
834 | $response->add_links( $links ); |
||
835 | |||
836 | if ( ! empty( $links['self']['href'] ) ) { |
||
837 | $actions = $this->get_available_actions( $invoice, $request ); |
||
838 | |||
839 | $self = $links['self']['href']; |
||
840 | |||
841 | foreach ( $actions as $rel ) { |
||
842 | $response->add_link( $rel, $self ); |
||
843 | } |
||
844 | } |
||
845 | |||
846 | /** |
||
847 | * Filters the invoice data for a response. |
||
848 | * |
||
849 | * @since 1.0.13 |
||
850 | * |
||
851 | * @param WP_REST_Response $response The response object. |
||
852 | * @param WPInv_Invoice $invoice The invoice object. |
||
853 | * @param WP_REST_Request $request Request object. |
||
854 | */ |
||
855 | return apply_filters( "wpinv_rest_prepare_invoice", $response, $invoice, $request ); |
||
856 | } |
||
857 | |||
858 | /** |
||
859 | * Gets an array of fields to be included on the response. |
||
860 | * |
||
861 | * Included fields are based on item schema and `_fields=` request argument. |
||
862 | * |
||
863 | * @since 1.0.13 |
||
864 | * |
||
865 | * @param WP_REST_Request $request Full details about the request. |
||
866 | * @return array Fields to be included in the response. |
||
867 | */ |
||
868 | public function get_fields_for_response( $request ) { |
||
869 | $schema = $this->get_item_schema(); |
||
870 | $properties = isset( $schema['properties'] ) ? $schema['properties'] : array(); |
||
871 | |||
872 | $additional_fields = $this->get_additional_fields(); |
||
873 | foreach ( $additional_fields as $field_name => $field_options ) { |
||
874 | // For back-compat, include any field with an empty schema |
||
875 | // because it won't be present in $this->get_item_schema(). |
||
876 | if ( is_null( $field_options['schema'] ) ) { |
||
877 | $properties[ $field_name ] = $field_options; |
||
878 | } |
||
879 | } |
||
880 | |||
881 | // Exclude fields that specify a different context than the request context. |
||
882 | $context = $request['context']; |
||
883 | if ( $context ) { |
||
884 | foreach ( $properties as $name => $options ) { |
||
885 | if ( ! empty( $options['context'] ) && ! in_array( $context, $options['context'], true ) ) { |
||
886 | unset( $properties[ $name ] ); |
||
887 | } |
||
888 | } |
||
889 | } |
||
890 | |||
891 | $fields = array_keys( $properties ); |
||
892 | |||
893 | if ( ! isset( $request['_fields'] ) ) { |
||
894 | return $fields; |
||
895 | } |
||
896 | $requested_fields = wpinv_parse_list( $request['_fields'] ); |
||
897 | if ( 0 === count( $requested_fields ) ) { |
||
898 | return $fields; |
||
899 | } |
||
900 | // Trim off outside whitespace from the comma delimited list. |
||
901 | $requested_fields = array_map( 'trim', $requested_fields ); |
||
902 | // Always persist 'id', because it can be needed for add_additional_fields_to_object(). |
||
903 | if ( in_array( 'id', $fields, true ) ) { |
||
904 | $requested_fields[] = 'id'; |
||
905 | } |
||
906 | // Return the list of all requested fields which appear in the schema. |
||
907 | return array_reduce( |
||
908 | $requested_fields, |
||
909 | function( $response_fields, $field ) use ( $fields ) { |
||
910 | if ( in_array( $field, $fields, true ) ) { |
||
911 | $response_fields[] = $field; |
||
912 | return $response_fields; |
||
913 | } |
||
914 | // Check for nested fields if $field is not a direct match. |
||
915 | $nested_fields = explode( '.', $field ); |
||
916 | // A nested field is included so long as its top-level property is |
||
917 | // present in the schema. |
||
918 | if ( in_array( $nested_fields[0], $fields, true ) ) { |
||
919 | $response_fields[] = $field; |
||
920 | } |
||
921 | return $response_fields; |
||
922 | }, |
||
923 | array() |
||
924 | ); |
||
925 | } |
||
926 | |||
927 | /** |
||
928 | * Retrieves the invoice's schema, conforming to JSON Schema. |
||
929 | * |
||
930 | * @since 1.0.13 |
||
931 | * |
||
932 | * @return array Invoice schema data. |
||
933 | */ |
||
934 | public function get_item_schema() { |
||
1233 | } |
||
1234 | |||
1235 | /** |
||
1236 | * Retrieve Link Description Objects that should be added to the Schema for the invoices collection. |
||
1237 | * |
||
1238 | * @since 1.0.13 |
||
1239 | * |
||
1240 | * @return array |
||
1241 | */ |
||
1242 | protected function get_schema_links() { |
||
1278 | } |
||
1279 | |||
1280 | /** |
||
1281 | * Prepares links for the request. |
||
1282 | * |
||
1283 | * @since 1.0.13 |
||
1284 | * |
||
1285 | * @param WPInv_Invoice $invoice Invoice Object. |
||
1286 | * @return array Links for the given invoice. |
||
1287 | */ |
||
1288 | protected function prepare_links( $invoice ) { |
||
1320 | |||
1321 | } |
||
1322 | |||
1323 | /** |
||
1324 | * Get the link relations available for the post and current user. |
||
1325 | * |
||
1326 | * @since 1.0.13 |
||
1327 | * |
||
1328 | * @param WPInv_Invoice $invoice Invoice object. |
||
1329 | * @param WP_REST_Request $request Request object. |
||
1330 | * @return array List of link relations. |
||
1331 | */ |
||
1332 | protected function get_available_actions( $invoice, $request ) { |
||
1363 | } |
||
1364 | |||
1365 | /** |
||
1366 | * Sanitizes and validates the list of post statuses. |
||
1367 | * |
||
1368 | * @since 1.0.13 |
||
1369 | * |
||
1370 | * @param string|array $statuses One or more post statuses. |
||
1371 | * @param WP_REST_Request $request Full details about the request. |
||
1372 | * @param string $parameter Additional parameter to pass to validation. |
||
1373 | * @return array|WP_Error A list of valid statuses, otherwise WP_Error object. |
||
1374 | */ |
||
1375 | public function sanitize_post_statuses( $statuses, $request, $parameter ) { |
||
1380 | |||
1381 | } |
||
1382 | |||
1383 | } |