Skip to content

Commit

Permalink
rerfactor rest api controllers
Browse files Browse the repository at this point in the history
  • Loading branch information
kilbot committed May 1, 2024
1 parent 4a0df87 commit d77f551
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 312 deletions.
113 changes: 67 additions & 46 deletions includes/API.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,37 +29,15 @@ class API {
protected $controllers = array();

/**
* @var
*/
protected $wc_rest_api_handler;

/**
* Flag to check if authentication has been checked.
*
* @var bool
*/
protected $is_auth_checked = false;


public function __construct() {
// Init and register routes for the WCPOS REST API
$this->controllers = array(
// woocommerce pos rest api controllers
'auth' => new API\Auth(),
'settings' => new API\Settings(),
'stores' => new API\Stores(),

// extend WC REST API controllers
'products' => new API\Products_Controller(),
'product_variations' => new API\Product_Variations_Controller(),
'orders' => new API\Orders_Controller(),
'customers' => new API\Customers_Controller(),
'product_tags' => new API\Product_Tags_Controller(),
'product_categories' => new API\Product_Categories_Controller(),
'taxes' => new API\Taxes_Controller(),
);

foreach ( $this->controllers as $key => $controller_class ) {
$controller_class->register_routes();
}
$this->register_routes();

// Allows requests from WCPOS Desktop and Mobile Apps
add_filter( 'rest_allowed_cors_headers', array( $this, 'rest_allowed_cors_headers' ), 10, 1 );
Expand All @@ -82,6 +60,58 @@ public function __construct() {
$this->prevent_messages();
}

/**
* Register routes for all controllers.
*/
public function register_routes() {
/**
* Filter the list of controller classes used in the WooCommerce POS REST API.
*
* This filter allows customizing or extending the set of controller classes that handle
* REST API routes for the WooCommerce POS. By filtering these controllers, plugins can
* modify existing endpoints or add new controllers for additional functionality.
*
* @since 1.5.0
*
* @param array $controllers Associative array of controller identifiers to their corresponding class names.
* - 'auth' => Fully qualified name of the class handling authentication.
* - 'settings' => Fully qualified name of the class handling settings.
* - 'stores' => Fully qualified name of the class handling stores management.
* - 'products' => Fully qualified name of the class handling products.
* - 'product_variations' => Fully qualified name of the class handling product variations.
* - 'orders' => Fully qualified name of the class handling orders.
* - 'customers' => Fully qualified name of the class handling customers.
* - 'product_tags' => Fully qualified name of the class handling product tags.
* - 'product_categories' => Fully qualified name of the class handling product categories.
* - 'taxes' => Fully qualified name of the class handling taxes.
*/
$classes = apply_filters(
'woocommerce_pos_rest_api_controllers',
array(
// woocommerce pos rest api controllers.
'auth' => API\Auth::class,
'settings' => API\Settings::class,
'stores' => API\Stores::class,

// extend WC REST API controllers.
'products' => API\Products_Controller::class,
'product_variations' => API\Product_Variations_Controller::class,
'orders' => API\Orders_Controller::class,
'customers' => API\Customers_Controller::class,
'product_tags' => API\Product_Tags_Controller::class,
'product_categories' => API\Product_Categories_Controller::class,
'taxes' => API\Taxes_Controller::class,
)
);

foreach ( $classes as $key => $class ) {
if ( class_exists( $class ) ) {
$this->controllers[ $key ] = new $class();
$this->controllers[ $key ]->register_routes();
}
}
}

/**
* Add CORS headers to the REST API response.
*
Expand Down Expand Up @@ -286,27 +316,16 @@ private function shorten_param_array( $param_value, $max_length ) {
* @return mixed
*/
public function rest_dispatch_request( $dispatch_result, $request, $route, $handler ) {
if ( isset( $handler['callback'] ) && \is_array( $handler['callback'] ) && isset( $handler['callback'][0] ) ) {
/*
* If $handler['callback'][0] matches one of our controllers we add a filter for $dispatch_result.
* This allows us to conditionally init woocommerce hooks in the controller.
*/
foreach ( $this->controllers as $key => $controller_class ) {
if ( $handler['callback'][0] === $controller_class ) {
/**
* Filters the dispatch result for a request.
*
* The dynamic portion of the hook name, `$key`, refers to the identifier of the controller.
*
* @since 1.4.0
*
* @param mixed $dispatch_result The dispatch result.
* @param WP_REST_Request $request The request instance.
* @param string $route The route being dispatched.
* @param array $handler The handler for the route.
*/
$dispatch_result = apply_filters( "woocommerce_pos_rest_dispatch_{$key}_request", $dispatch_result, $request, $route, $handler );

if ( isset( $handler['callback'] ) && is_array( $handler['callback'] ) && isset( $handler['callback'][0] ) ) {
$controller = $handler['callback'][0];

// Check if the controller object is one of our registered controllers.
foreach ( $this->controllers as $key => $wcpos_controller ) {
if ( $controller === $wcpos_controller ) {
// Check if the controller has a 'wcpos_dispatch_request' method.
if ( method_exists( $controller, 'wcpos_dispatch_request' ) ) {
return $controller->wcpos_dispatch_request( $dispatch_result, $request, $route, $handler );
}
break;
}
}
Expand All @@ -324,6 +343,8 @@ private function prevent_messages(): void {
}

/**
* Check the Authorization header for a Bearer token.
*
* @param false|int $user_id User ID if one has been determined, false otherwise.
*
* @return int|WP_Error
Expand Down
53 changes: 19 additions & 34 deletions includes/API/Customers_Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,28 @@ class Customers_Controller extends WC_REST_Customers_Controller {
protected $wcpos_request;

/**
* Constructor.
* Dispatch request to parent controller, or override if needed.
*
* @param mixed $dispatch_result Dispatch result, will be used if not empty.
* @param WP_REST_Request $request Request used to generate the response.
* @param string $route Route matched for the request.
* @param array $handler Route handler used for the request.
*/
public function __construct() {
add_filter( 'woocommerce_pos_rest_dispatch_customers_request', array( $this, 'wcpos_dispatch_request' ), 10, 4 );
public function wcpos_dispatch_request( $dispatch_result, WP_REST_Request $request, $route, $handler ) {
$this->wcpos_request = $request;

if ( method_exists( parent::class, '__construct' ) ) {
parent::__construct();
add_filter( 'woocommerce_rest_prepare_customer', array( $this, 'wcpos_customer_response' ), 10, 3 );
add_filter( 'woocommerce_rest_customer_query', array( $this, 'wcpos_customer_query' ), 10, 2 );

/**
* Check if the request is for all customers and if the 'posts_per_page' is set to -1.
* Optimised query for getting all customer IDs.
*/
if ( $request->get_param( 'posts_per_page' ) == -1 && $request->get_param( 'fields' ) !== null ) {
return $this->wcpos_get_all_posts( $request->get_param( 'fields' ) );
}

return $dispatch_result;
}

/**
Expand Down Expand Up @@ -160,35 +174,6 @@ public function wcpos_validate_billing_email( WP_REST_Request $request ) {
return true;
}

/**
* Dispatch request to parent controller, or override if needed.
*
* @param mixed $dispatch_result Dispatch result, will be used if not empty.
* @param WP_REST_Request $request Request used to generate the response.
* @param string $route Route matched for the request.
* @param array $handler Route handler used for the request.
*/
public function wcpos_dispatch_request( $dispatch_result, WP_REST_Request $request, $route, $handler ) {
$this->wcpos_request = $request;
$this->wcpos_register_wc_rest_api_hooks();
$params = $request->get_params();

// Optimised query for getting all user IDs.
if ( isset( $params['posts_per_page'] ) && -1 == $params['posts_per_page'] && isset( $params['fields'] ) ) {
$dispatch_result = $this->wcpos_get_all_posts( $params['fields'] );
}

return $dispatch_result;
}

/**
* Register hooks to modify WC REST API response.
*/
public function wcpos_register_wc_rest_api_hooks(): void {
add_filter( 'woocommerce_rest_prepare_customer', array( $this, 'wcpos_customer_response' ), 10, 3 );
add_filter( 'woocommerce_rest_customer_query', array( $this, 'wcpos_customer_query' ), 10, 2 );
}

/**
* Filter customer data returned from the REST API.
*
Expand Down
78 changes: 35 additions & 43 deletions includes/API/Orders_Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,41 @@ class Orders_Controller extends WC_REST_Orders_Controller {
* Constructor.
*/
public function __construct() {
add_filter( 'woocommerce_pos_rest_dispatch_orders_request', array( $this, 'wcpos_dispatch_request' ), 10, 4 );
$this->hpos_enabled = class_exists( OrderUtil::class ) && OrderUtil::custom_orders_table_usage_is_enabled();

if ( method_exists( parent::class, '__construct' ) ) {
parent::__construct();
}
}

/**
* Dispatch request to parent controller, or override if needed.
*
* @param mixed $dispatch_result Dispatch result, will be used if not empty.
* @param WP_REST_Request $request Request used to generate the response.
* @param string $route Route matched for the request.
* @param array $handler Route handler used for the request.
*/
public function wcpos_dispatch_request( $dispatch_result, WP_REST_Request $request, $route, $handler ) {
$this->wcpos_request = $request;

add_filter( 'woocommerce_rest_prepare_shop_order_object', array( $this, 'wcpos_order_response' ), 10, 3 );
add_filter( 'woocommerce_order_get_items', array( $this, 'wcpos_order_get_items' ), 10, 3 );
add_action( 'woocommerce_before_order_object_save', array( $this, 'wcpos_before_order_object_save' ), 10, 2 );
add_filter( 'woocommerce_rest_shop_order_object_query', array( $this, 'wcpos_shop_order_query' ), 10, 2 );
add_filter( 'option_woocommerce_tax_based_on', array( $this, 'wcpos_tax_based_on' ), 10, 2 );

/**
* Check if the request is for all orders and if the 'posts_per_page' is set to -1.
* Optimised query for getting all order IDs.
*/
if ( $request->get_param( 'posts_per_page' ) == -1 && $request->get_param( 'fields' ) !== null ) {
return $this->wcpos_get_all_posts( $request->get_param( 'fields' ) );
}

return $dispatch_result;
}

/**
* Register routes.
*/
Expand Down Expand Up @@ -126,26 +153,26 @@ public function register_routes() {
public function get_item_schema() {
$schema = parent::get_item_schema();

// Add barcode property to the schema
// Add barcode property to the schema.
$schema['properties']['barcode'] = array(
'description' => __( 'Barcode', 'woocommerce-pos' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => false,
);

// Check and remove email format validation from the billing property
// Check and remove email format validation from the billing property.
if ( isset( $schema['properties']['billing']['properties']['email']['format'] ) ) {
unset( $schema['properties']['billing']['properties']['email']['format'] );
}

// Modify line_items->parent_name to accept 'string' or 'null'
// Modify line_items->parent_name to accept 'string' or 'null'.
if ( isset( $schema['properties']['line_items'] ) &&
\is_array( $schema['properties']['line_items']['items']['properties'] ) ) {
$schema['properties']['line_items']['items']['properties']['parent_name']['type'] = array( 'string', 'null' );
}

// Check for 'stock_quantity' and allow decimal
// Check for 'stock_quantity' and allow decimal.
if ( $this->wcpos_allow_decimal_quantities() &&
isset( $schema['properties']['line_items'] ) &&
\is_array( $schema['properties']['line_items']['items']['properties'] ) ) {
Expand All @@ -169,10 +196,10 @@ public function create_item( $request ) {
return $valid_email;
}

// Set the creating flag, used in woocommerce_before_order_object_save
// Set the creating flag, used in woocommerce_before_order_object_save.
$this->is_creating = true;

// Proceed with the parent method to handle the creation
// Proceed with the parent method to handle the creation.
return parent::create_item( $request );
}

Expand All @@ -189,7 +216,7 @@ public function update_item( $request ) {
return $valid_email;
}

// Proceed with the parent method to handle the creation
// Proceed with the parent method to handle the creation.
return parent::update_item( $request );
}

Expand Down Expand Up @@ -383,28 +410,6 @@ public function wcpos_recipient_email_address() {
return $this->wcpos_request['email'];
}


/**
* Dispatch request to parent controller, or override if needed.
*
* @param mixed $dispatch_result Dispatch result, will be used if not empty.
* @param WP_REST_Request $request Request used to generate the response.
* @param string $route Route matched for the request.
* @param array $handler Route handler used for the request.
*/
public function wcpos_dispatch_request( $dispatch_result, WP_REST_Request $request, $route, $handler ) {
$this->wcpos_request = $request;
$this->wcpos_register_wc_rest_api_hooks( $request );
$params = $request->get_params();

// Optimised query for getting all product IDs
if ( isset( $params['posts_per_page'] ) && -1 == $params['posts_per_page'] && isset( $params['fields'] ) ) {
$dispatch_result = $this->wcpos_get_all_posts( $params['fields'] );
}

return $dispatch_result;
}

/**
*
*/
Expand Down Expand Up @@ -452,19 +457,6 @@ public function wcpos_get_public_order_statuses_schema() {
return $schema;
}

/**
* Register hooks to modify WC REST API response.
*
* @param WP_REST_Request $request
*/
public function wcpos_register_wc_rest_api_hooks( WP_REST_Request $request ): void {
add_filter( 'woocommerce_rest_prepare_shop_order_object', array( $this, 'wcpos_order_response' ), 10, 3 );
add_filter( 'woocommerce_order_get_items', array( $this, 'wcpos_order_get_items' ), 10, 3 );
add_action( 'woocommerce_before_order_object_save', array( $this, 'wcpos_before_order_object_save' ), 10, 2 );
add_filter( 'woocommerce_rest_shop_order_object_query', array( $this, 'wcpos_shop_order_query' ), 10, 2 );
add_filter( 'option_woocommerce_tax_based_on', array( $this, 'wcpos_tax_based_on' ), 10, 2 );
}

/**
* @param WP_REST_Response $response The response object.
* @param WC_Abstract_Order $order Object data.
Expand Down
Loading

0 comments on commit d77f551

Please sign in to comment.