Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Store API: Refactored validation handling and introduced woocommerce_store_api_cart_errors hook #5904

Merged
merged 33 commits into from
Mar 2, 2022

Conversation

xristos3490
Copy link
Member

@xristos3490 xristos3490 commented Feb 21, 2022

This refactor is based on how the system handles the InvalidStockLevelsInCartException and aims to create a more DRY error validation architecture.

Currently, when there are multiple _(stock-related)_errors raised from the cart contents, the system will group them in a single WP_Error instance with a "409 Conflict" code. During the REST response, these errors are deconstructed into multiple error keys. One error/key.

This PR replaces the InvalidStockLevelsInCartException with a more generic InvalidCartException that should handle every validation-related error from the core, stock, or 3PD.

In addition, the InvalidCartException is designed to handle multiple errors in its own WP_Error.

When a validate_xxxx method throws an InvalidCartException containing multiple errors:

  • The related cart errors getter will catch it and deconstruct its errors into multiple WP_Error objects; the final REST response will be the same.
  • The checkout route will catch it and continue with the same approach; the difference from the InvalidStockLevelsInCartException is that the system will have the original error codes instead of "409 Conflict".

In a nutshell:

  • Error getters are try...catch wrappers of the validate-related methods (DRY).
  • Introduces a new generic InvalidCartException class to be used in all errors related to the cart validity.
  • The new exception type supports multiple errors on a single cart check.
  • Uses as a primary source of validation all the validate_xxxx methods.
  • You can still break the checkout block if you return an Exception from the POST response context; this probably needs a mechanism to prevent it.
  • The __experimental_woocommerce_store_api_validate_cart and the woocommerce_check_cart_items are connected. It seems like a good path for deprecating the latter in the API. See Next Steps # 2
  • The newly created __experimental_woocommerce_store_api_validate_cart hook is called in the cart and checkout context to create consistency.

cart_validation_refactor

What's changed

  • When multiple errors are thrown from the "Place Order" flow, each will retain a readable string as error-code instead of the generic 409 error.
  • RouteException is now handled in both the cart and checkout flows, as previously, were only held in the cart flow.

Example 3PD cart validation usage:

add_filter( '__experimental_woocommerce_store_api_validate_cart', 'test_cart_errors' );
function test_cart_errors( $cart ) {

    $error = new \WP_Error();
    // First error.
    $error->add(
        'test_error_1',
        'Cart error #1'
    );
    // Second error.
    $error->add(
        'test_error_2',
        'Cart error #2'
    );

    throw new \Automattic\WooCommerce\Blocks\StoreApi\Utilities\InvalidCartException(
        'test_plugin_error_code',
        $error,
        409
    );
}

The snippet above adds multiple errors, and the result is handled accordingly: https://d.pr/i/vPircs (checkout) and https://d.pr/i/alWAW9 (cart).

A present use-case:

Conditional Shipping and Payments extension is a condition-based restriction system that could potentially produce complex business restrictions. Throwing a WP_Error object containing multiple errors is crucial for correctly handling all situations.

Next steps:

  • Add acontext argument in validate_cart() and control whether the __experimental_woocommerce_store_api_validate_cart or the woocommerce_check_cart_items should fire. Perhaps, for performance reasons, we need to only run the woocommerce_check_cart_items legacy hook in the checkout context to avoid handling WC notices to exceptions all the time.
  • We could avoid adding a context argument by moving the woocommerce_check_cart_items directly inside the Checkout::get_route_post_response; it will be deprecated, so it shouldn't be a clean-code issue.

Accessibility

Other Checks

  • I've updated this doc for any feature flags or experimental interfaces implemented in this pull request.
  • I tagged two reviewers because this PR makes queries to the database or I think it might have some security impact.

Testing

Automated Tests

  • Changes in this PR are covered by Automated Tests.
    • Unit tests
    • E2E tests

User Facing Testing

None.

Changelog

Introduce the InvalidCartException for handling cart validation.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 21, 2022

Size Change: 0 B

Total Size: 863 kB

ℹ️ View Unchanged
Filename Size
build/active-filters-frontend.js 6.27 kB
build/active-filters.js 6.94 kB
build/all-products-frontend.js 18.6 kB
build/all-products.js 33.9 kB
build/all-reviews.js 8.03 kB
build/atomic-block-components/add-to-cart--atomic-block-components/button--atomic-block-components/catego--90468e1a.js 223 B
build/atomic-block-components/add-to-cart--atomic-block-components/button--atomic-block-components/image---a7e2bb9b.js 2.65 kB
build/atomic-block-components/add-to-cart-frontend.js 7.01 kB
build/atomic-block-components/add-to-cart.js 7.49 kB
build/atomic-block-components/button--atomic-block-components/category-list--atomic-block-components/imag--f11cdc7a.js 498 B
build/atomic-block-components/button-frontend.js 2.08 kB
build/atomic-block-components/button.js 2.3 kB
build/atomic-block-components/category-list-frontend.js 920 B
build/atomic-block-components/category-list.js 501 B
build/atomic-block-components/image-frontend.js 1.86 kB
build/atomic-block-components/image.js 1.09 kB
build/atomic-block-components/price-frontend.js 1.93 kB
build/atomic-block-components/price.js 1.51 kB
build/atomic-block-components/rating-frontend.js 1.13 kB
build/atomic-block-components/rating.js 718 B
build/atomic-block-components/sale-badge-frontend.js 1.09 kB
build/atomic-block-components/sale-badge.js 683 B
build/atomic-block-components/sku-frontend.js 385 B
build/atomic-block-components/sku.js 386 B
build/atomic-block-components/stock-indicator-frontend.js 1.03 kB
build/atomic-block-components/stock-indicator.js 624 B
build/atomic-block-components/summary-frontend.js 1.34 kB
build/atomic-block-components/summary.js 923 B
build/atomic-block-components/tag-list-frontend.js 921 B
build/atomic-block-components/tag-list.js 499 B
build/atomic-block-components/title-frontend.js 1.31 kB
build/atomic-block-components/title.js 932 B
build/attribute-filter-frontend.js 16.8 kB
build/attribute-filter.js 13 kB
build/blocks-checkout.js 17.2 kB
build/cart-blocks/accepted-payment-methods-frontend.js 1.14 kB
build/cart-blocks/checkout-button-frontend.js 1.15 kB
build/cart-blocks/empty-cart-frontend.js 347 B
build/cart-blocks/express-payment-frontend.js 5.18 kB
build/cart-blocks/filled-cart-frontend.js 767 B
build/cart-blocks/items-frontend.js 299 B
build/cart-blocks/line-items-frontend.js 5.5 kB
build/cart-blocks/order-summary-frontend.js 8.88 kB
build/cart-blocks/totals-frontend.js 320 B
build/cart-frontend.js 45.2 kB
build/cart.js 43.5 kB
build/checkout-blocks/actions-frontend.js 1.41 kB
build/checkout-blocks/billing-address--checkout-blocks/shipping-address-frontend.js 4.13 kB
build/checkout-blocks/billing-address-frontend.js 891 B
build/checkout-blocks/contact-information-frontend.js 2.85 kB
build/checkout-blocks/express-payment-frontend.js 5.48 kB
build/checkout-blocks/fields-frontend.js 344 B
build/checkout-blocks/order-note-frontend.js 1.13 kB
build/checkout-blocks/order-summary-frontend.js 11.3 kB
build/checkout-blocks/payment-frontend.js 7.77 kB
build/checkout-blocks/shipping-address-frontend.js 997 B
build/checkout-blocks/shipping-methods-frontend.js 4.73 kB
build/checkout-blocks/terms-frontend.js 1.22 kB
build/checkout-blocks/totals-frontend.js 323 B
build/checkout-frontend.js 47.4 kB
build/checkout.js 44.7 kB
build/featured-category.js 8.62 kB
build/featured-product.js 9.73 kB
build/handpicked-products.js 7.1 kB
build/legacy-template.js 2.18 kB
build/mini-cart-component-frontend.js 16 kB
build/mini-cart-contents-block/empty-cart-frontend.js 363 B
build/mini-cart-contents-block/filled-cart-frontend.js 222 B
build/mini-cart-contents-block/footer--mini-cart-contents-block/products-table-frontend.js 5.33 kB
build/mini-cart-contents-block/footer-frontend.js 6.27 kB
build/mini-cart-contents-block/items-frontend.js 206 B
build/mini-cart-contents-block/products-table-frontend.js 5.33 kB
build/mini-cart-contents-block/shopping-button-frontend.js 260 B
build/mini-cart-contents-block/title-frontend.js 348 B
build/mini-cart-contents.js 24.2 kB
build/mini-cart-frontend.js 1.71 kB
build/mini-cart.js 6.39 kB
build/price-filter-frontend.js 12.5 kB
build/price-filter.js 8.47 kB
build/price-format.js 1.19 kB
build/product-best-sellers.js 7.37 kB
build/product-categories.js 3.17 kB
build/product-category.js 8.49 kB
build/product-new.js 7.67 kB
build/product-on-sale.js 7.99 kB
build/product-search.js 2.19 kB
build/product-tag.js 7.81 kB
build/product-top-rated.js 7.9 kB
build/products-by-attribute.js 8.38 kB
build/reviews-by-category.js 11.4 kB
build/reviews-by-product.js 12.6 kB
build/reviews-frontend.js 7.34 kB
build/single-product-frontend.js 22 kB
build/single-product.js 10 kB
build/stock-filter-frontend.js 6.5 kB
build/stock-filter.js 6.56 kB
build/vendors--atomic-block-components/add-to-cart--cart-blocks/order-summary--checkout-blocks/billing-ad--c5eb4dcd-frontend.js 19 kB
build/vendors--atomic-block-components/add-to-cart-frontend.js 7.51 kB
build/vendors--atomic-block-components/price--cart-blocks/line-items--cart-blocks/order-summary--checkout--194c50bf-frontend.js 5.26 kB
build/vendors--cart-blocks/line-items--checkout-blocks/order-summary--mini-cart-contents-block/products-table-frontend.js 3.14 kB
build/vendors--cart-blocks/order-summary--checkout-blocks/billing-address--checkout-blocks/order-summary---eb4d2cec-frontend.js 4.74 kB
build/vendors--mini-cart-contents-block/footer--mini-cart-contents-block/products-table-frontend.js 7.72 kB
build/wc-blocks-data.js 9.78 kB
build/wc-blocks-editor-style-rtl.css 4.84 kB
build/wc-blocks-editor-style.css 4.84 kB
build/wc-blocks-google-analytics.js 1.56 kB
build/wc-blocks-middleware.js 953 B
build/wc-blocks-registry.js 2.7 kB
build/wc-blocks-shared-context.js 1.52 kB
build/wc-blocks-shared-hocs.js 1.14 kB
build/wc-blocks-style-rtl.css 22.2 kB
build/wc-blocks-style.css 22.2 kB
build/wc-blocks-vendors-style-rtl.css 1.28 kB
build/wc-blocks-vendors-style.css 1.28 kB
build/wc-blocks-vendors.js 69.4 kB
build/wc-blocks.js 2.62 kB
build/wc-payment-method-bacs.js 816 B
build/wc-payment-method-cheque.js 811 B
build/wc-payment-method-cod.js 909 B
build/wc-payment-method-paypal.js 837 B
build/wc-settings.js 2.61 kB

compressed-size-action

@xristos3490 xristos3490 force-pushed the refactor/cart-order-validation-handling branch from 578fcae to 8115fa4 Compare February 21, 2022 10:55
@manospsyx
Copy link

This pretty much supersedes #5874 (it is a bit broader in scope as it is meant to add some extra clarity around ongoing discussions on extensibility, consistency, and code re-use).

@mikejolley mikejolley added focus: rest api Work impacting REST api routes. status: needs review block: checkout Issues related to the checkout block. labels Feb 23, 2022
Copy link
Member

@mikejolley mikejolley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some initial feedback. I think the main thing we need to do is clean up the approach to WP_Error/Exception because there is a bunch of to-and-fro between the two types.

src/StoreApi/Routes/AbstractRoute.php Outdated Show resolved Hide resolved
src/StoreApi/Utilities/InvalidCartException.php Outdated Show resolved Hide resolved
src/StoreApi/Utilities/CartController.php Outdated Show resolved Hide resolved
src/StoreApi/Utilities/CartController.php Outdated Show resolved Hide resolved
@xristos3490
Copy link
Member Author

xristos3490 commented Feb 23, 2022

I tried to merge with trunk in order to fix the versioning namespace, but I got stuck on some unrelated PHPCS errors after the merge -- will look into this tomorrow.

Update: This branch is in line with trunk. Also updated the namespaces.

@woocommerce woocommerce deleted a comment from github-actions bot Feb 24, 2022
@PanosSynetos PanosSynetos force-pushed the refactor/cart-order-validation-handling branch from 682e19b to 6381251 Compare February 24, 2022 12:04
@xristos3490 xristos3490 force-pushed the refactor/cart-order-validation-handling branch from 2a4ac9d to 492ca88 Compare March 1, 2022 10:36
Manos Psychogyiopoulos and others added 12 commits March 2, 2022 11:09
This action can be used by third party developers to add extra 'errors' in cart route responses. This is meant to function as a replacement of the legacy 'woocommerce_check_cart_items' hook.
The new action can be used to modify the finalized draft order object.
Additionally, developers can use it to throw a RouteException in order to prevent access to the checkout block.

The PR also shuffles some existing code that checks the order instance and sets the draft order ID before the 'woocommerce_blocks_checkout_update_order_meta' gets fired.
…er_meta' docblock on the effect of exceptions thrown from callbacks
@mikejolley mikejolley force-pushed the refactor/cart-order-validation-handling branch from c2095ce to 83bbf2d Compare March 2, 2022 11:22
@mikejolley mikejolley changed the title Refactor cart/order validation handling Store API: Refactored validation handling and introduced __experimental_woocommerce_store_api_cart_errors hook Mar 2, 2022
Copy link
Member

@mikejolley mikejolley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good now, up to date with trunk, smoke tested the new (and old) hooks, 🚢

@github-actions github-actions bot added this to the 7.2.0 milestone Mar 2, 2022
@mikejolley mikejolley changed the title Store API: Refactored validation handling and introduced __experimental_woocommerce_store_api_cart_errors hook Store API: Refactored validation handling and introduced woocommerce_store_api_cart_errors hook Mar 2, 2022
@mikejolley mikejolley merged commit cdb966d into trunk Mar 2, 2022
@mikejolley mikejolley deleted the refactor/cart-order-validation-handling branch March 2, 2022 12:21
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
block: checkout Issues related to the checkout block. focus: rest api Work impacting REST api routes.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants