-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor to support HPOS #71
base: master
Are you sure you want to change the base?
Conversation
@maxfrederiksen-mondido is this ready for review or still WIP? |
@nuttmeister I would say WIP since I can't test it yet locally. However if we can find a way to test on staging then yes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conditionals can be eliminated by introducing polymorphism. This will have the following benefits:
- The client code, i.e. the callers, will be less complex
- All code related to a particular order storage technology (HPOS or CPT) will be in a single location and not spread out across the code base.
- Less duplicated code
One polymorphic solution we could use is to introduce an abstract OrderStorageTechnology
base class and have concrete implementations HPOSOrderStorage
and CPTOrderStorage
. A client could then call it like so:
OrderStorageTechnology::current()->delete_meta_data($order, '_mondido_invoice_address');
OrderStorageTechnology::current()->update_meta_data($order, '_mondido_invoice_address', $address);
OrderStorageTechnology::current()->save($order);
The CPTOrderStorage::save
method would have an empty implementation since saving seems to be implied by each individual mutation. I guess this is one reason for the lower performance of the legacy API.
To reduce the duplication further we could even introduce our own OrderStorage
class and use it like so:
OrderStorage::get().replace_meta_data($order, '_mondido_invoice_address', $address);
The implementation would reuse the OrderStorageTechnology
:
class OrderStorage
{
// ... Static factory method, technology field and constructor here
public function replace_meta_data($order, $key, $value)
{
$this->technology->delete_meta_data($order, $key);
$this->technology->update_meta_data($order, $key, $value);
$this->technology->save($order);
}
// More useful methods would go here
}
With this implementation, the only if-statement is in OrderStorageTechnology::current()
, the client code is much simpler and each participating class has a small and well defined scope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks good. Please consider my comments.
@@ -58,21 +58,9 @@ public function __construct( $the_order ) { | |||
if ( FALSE === $the_order ) { | |||
$the_order = $post; | |||
} elseif ( is_numeric( $the_order ) ) { | |||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we remove the conditional here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file will be removed after upgrade so no need to add any if checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is upgrading WooCommerce a prerequisite for using HPOS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
October 2023
From WooCommerce 8.2, released on October 2023, High-Performance Order Storage (HPOS) is officially flagged as stable and will be enabled by default for new installations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have tested everything on the latest version 8.7. So ideally if we get merchants to upgrade to the same one we should be safe. Hopefully the newer versions will also work, aka 9.0, but we should encourage our merchants to use 8.7 for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What will happen if the merchant uses our updated plugin without updating their WooCommerce version? Do we really want to enforce all merchants to upgrade their WooCommerce version to use the latest version of our plugin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is for us to be able to support HPOS and CPT at the same time, which is what this PR is about. Our merchants should till be able to run really old woo and it will work since it's backwards compatible. However, IMHO, i don't think it's good for them to be on old versions, like 2.2 etc. So if our plan is to ask those merchants to upgrade we might as well ask everyone.
Merchants that are using versions 8.2 or later will be able to activate HPOS directly. However they will need to also do some admin work since they need to sync orders between the tables etc, it's an easy process but still should be monitored by them and if any errors should come up they would need to contact us or Woocommerce.
@@ -31,6 +31,11 @@ public function __construct() { | |||
register_deactivation_hook( __FILE__, array( $this, 'flush_rewrite_rules' ) ); | |||
|
|||
// Actions | |||
add_action( 'before_woocommerce_init', function() { | |||
if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this call should move to either OrderStorageTechnology
or OrderUtil
so that we have all mentions of the custom orders table in a single location. However, if we move the logic we must pass __FILE__
as an argument to preserve the behavior, e.g. OrderStorageTechnology::declare_compatibility(__FILE__)
;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like it fits here since it's something that should be added before woocommerce init.
A very similar add_action call is made further down in that function:
"// WC_Order Compatibility for WC < 3.0
add_action( 'woocommerce_init', CLASS . '::add_compatibility' );"
Which is also for a one-off compatibility file, so i feel like it fits here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My idea was just to move the mention of the custom orders table to either OrderStorage
or OrderUtil
since that is an implementation detail of HPOS. Thinking of it now, an even better location is probably HPOSOrderStorage
. The call to add_action
is probably best kept here.
add_action( 'before_woocommerce_init', function() {
HPOSOrderStorage::declare_compatibility(__FILE__);
}
However, if you prefer the current solution I am fine with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove the "WIP" tag from title before merging. It'd confuse anyone going through commits in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good comments by @eric-thelin. I have nothing to add
|
||
use Automattic\WooCommerce\Utilities\OrderUtil; | ||
|
||
interface OrderStorageInterface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having Interface
in the name is ugly and violates the IS-A relationship to implementing classes. For instance, HPOSOrderStorage
implements OrderStorageInterface
but it is wrong to say that it "is a" OrderStorageInterface
. HPOSOrderStorage
is not an interface, it is a kind of order storage. The same is true for CPTOrderStorage
. Since both those classes are examples of order storage, it makes sense to use the name OrderStorage
for the shared interface.
If the problem is that we already use the name OrderStorage
as a placeholder for the current()
method, my suggestion is that we merge OrderStorageInterface
and OrderStorage
into an abstract class named OrderStorage
.
abstract class OrderStorage
{
public static function current(): OrderStorage
{
if (OrderUtil::custom_orders_table_usage_is_enabled()) {
return new HPOSOrderStorage();
} else {
return new CPTOrderStorage();
}
}
public abstract function get_meta_data($order, $meta_key, $meta_value);
public abstract function add_meta_data($order, $meta_key, $meta_value);
public abstract function update_meta_data($order, $meta_key, $meta_value);
public abstract function delete_meta_data($order, $meta_key);
public abstract function save($order);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's exactly the issue I saw with clashing names. Thanks for the input, learning a lot about OOP best practices here, great stuff :)
Function
(WIP) Refactor and make our plugin use latest HPOS so it still works in the future when they remove old way.
Business value
Making sure the plugins doesn't break when they deprecate current methods.
Security considerations
Not sure.
Implementation strategies
Not sure.
Rollback strategies
Rollback to latest version
Test
Tested locally connected to prod mondido admin.
Tested happy flow with cards.
Made sure syntax is correct and not breaking.
Steps taken
None yet.
Expected result
Working with new HPOS.