PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.17
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.17
1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 1.9.13 All 162 releases
woocommerce-pos / includes / API / V2 / Catalog_Proxy_Controller.php

Catalog_Proxy_Controller.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.17, at includes/API/V2/Catalog_Proxy_Controller.php

136 lines 5.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WCPOS sync read surface.
4 *
5 * @package WCPOS\WooCommercePOS\API\V2
6 */
7
8 namespace WCPOS\WooCommercePOS\API\V2;
9
10 use WCPOS\WooCommercePOS\API\V2\Proxy\Null_Proxy_Behavior;
11 use WCPOS\WooCommercePOS\API\V2\Proxy\Proxy_Behavior;
12 use WCPOS\WooCommercePOS\Sync\Api;
13 use WCPOS\WooCommercePOS\Sync\Collections;
14 use WCPOS\WooCommercePOS\Sync\Endpoint_Permissions;
15 use WCPOS\WooCommercePOS\Sync\Store_Scope;
16 use WP_REST_Controller;
17 use WP_REST_Request;
18 use WP_REST_Server;
19
20 // phpcs:disable Squiz.Commenting, Generic.Commenting -- Ported lab documentation is preserved verbatim.
21
22 /**
23 * Catalog proxy endpoints — route replication READS through our `{API_NAMESPACE}`
24 * namespace instead of hitting raw `wc/v3` directly (guardrail G4: replication is
25 * wrapped in our namespace so we can customize the request/response and
26 * duck-punch for replication WITHOUT editing wc/v3 or the client).
27 *
28 * Routes forward to their wc/v3 counterparts via `rest_do_request`, preserving
29 * query params except where WCPOS adapts them (such as multi-term customer search
30 * and the WCPOS-extended customer sorts),
31 * plus the underlying status + pagination headers
32 * (so the client's existing array-shaped parsing and `length < per_page`
33 * pagination keep working), then exposes a single `woocommerce_pos_sync_proxy_response`
34 * filter seam — `($data, $resource, $request)` — so replication can shape the
35 * batch in one place. Today it is a faithful pass-through; the point is the
36 * controlled seam + decoupling the client from wc/v3 routes/versioning.
37 *
38 * Per-object serialization customization (`woocommerce_pos_sync_serialized_product`
39 * etc.) stays on the per-id paths — variations/resolve/changes — where the WC
40 * object is actually loaded; this list proxy keeps wc/v3's own serialization and
41 * filters the batch as a whole.
42 */
43 class Catalog_Proxy_Controller extends WP_REST_Controller {
44 use Endpoint_Permissions;
45
46 /** Register every proxied collection route from the collection registry. */
47 public function register_routes(): void {
48 foreach ( self::resources() as $route => $meta ) {
49 $wc_route = $meta[0];
50 $resource = $meta[1];
51 $behavior_class = $meta[2];
52 register_rest_route(
53 Api::ROUTE_NAMESPACE,
54 '/' . ltrim( $route, '/' ),
55 array(
56 'methods' => WP_REST_Server::READABLE,
57 // Closure carries the target so the handler never has to re-derive
58 // it from the matched route — one handler, six wired routes.
59 'callback' => function ( WP_REST_Request $request ) use ( $wc_route, $resource, $behavior_class ) {
60 return $this->proxy( $request, $wc_route, $resource, new $behavior_class() );
61 },
62 'permission_callback' => array( $this, 'permissions_check' ),
63 )
64 );
65 }
66 }
67
68 /**
69 * Forward the request to $wc_route via rest_do_request (adapting query
70 * params where needed and preserving wc/v3 status/headers), then expose the batch through the
71 * replication seam filter. wc/v3 errors are forwarded unchanged so the
72 * client sees the same failure it would have seen hitting wc/v3 directly.
73 */
74 public function proxy( WP_REST_Request $request, string $wc_route, string $resource, ?Proxy_Behavior $behavior = null ) {
75 $behavior = $behavior ?? self::behavior_for( $resource );
76 $query_params = $behavior->forwarded_params( $request->get_query_params(), $request );
77 $inner = new WP_REST_Request( WP_REST_Server::READABLE, $wc_route );
78 unset( $query_params[ Store_Scope::PARAM ] );
79 $inner->set_query_params( $query_params );
80 // The till's store scope, republished as v1's `store_id` param (pro#425).
81 // This is the greedy catalog list pull, so it is what decides whether the
82 // products grid shows each store's own price or the web store's. Stamped
83 // after set_query_params so a scope is never wiped by the forwarded set.
84 Store_Scope::stamp( $inner );
85 $forward = static function () use ( $inner ) {
86 return Store_Scope::in_v2_lane( static fn() => rest_do_request( $inner ) );
87 };
88 $response = $behavior->around( $forward );
89 if ( $response->is_error() ) {
90 return $response;
91 }
92 $data = apply_filters( 'woocommerce_pos_sync_proxy_response', $response->get_data(), $resource, $request );
93 $response->set_data( $behavior->post_process( $data ) );
94
95 return $response;
96 }
97
98 /**
99 * our namespace route => [ wc/v3 route to forward to, resource slug for
100 * the seam ] — a PROJECTION of the registry's proxy capability (#421
101 * increment 4): the route/forward/slug vocabulary now has one home
102 * (Collections), and adding a proxied collection is one registry row.
103 *
104 * Orders proxy /orders here for the browser-window / targeted / query-total
105 * reads (the client assembles each document's uuid identity from the served
106 * payload); the checkpointed greedy order lane keeps its own cursor endpoint
107 * /orders/pull in Orders_Controller.
108 */
109 private static function resources(): array {
110 $resources = array();
111 foreach ( Collections::with( 'proxy' ) as $row ) {
112 $resources[ $row['proxy']['route'] ] = array(
113 $row['proxy']['wc_route'],
114 $row['proxy']['slug'],
115 $row['proxy']['behavior'],
116 );
117 }
118
119 return $resources;
120 }
121
122 /**
123 * Resolve behavior for direct proxy() callers that did not come through route registration.
124 *
125 * @param string $resource Proxy resource slug.
126 *
127 * @return Proxy_Behavior
128 */
129 private static function behavior_for( string $resource ): Proxy_Behavior {
130 $row = Collections::by_proxy_slug( $resource );
131 $class = $row['proxy']['behavior'] ?? Null_Proxy_Behavior::class;
132
133 return new $class();
134 }
135 }
136