SimpleCart + FormIt 4.2 compatibility hotfix (SimpleCart v2.6.1)

When FormIt 4.2.0 was released two weeks ago, its internals changed a bit. The change is subtle, and would not normally affect other extras that rely on FormIt, but unfortunately, it causes a flurry of errors in SimpleCart and a fatal error when checking out.

This issue was reported today, and after a bit of debugging, I’ve immediately made a SimpleCart 2.6.1 hotfix available to correct it.

If you have updated FormIt to 4.2 in the past two weeks, your checkout is likely broken, and you need to immediately upgrade SimpleCart to 2.6.1. This affects SimpleCart v2.4 and up.

I can’t upgrade to 2.6.1. How do I patch?

In the scCreateOrder snippet, change the following line (on line 9):

$sc = $modx->getService('simplecart','SimpleCart',$modx->getOption('simplecart.core_path',null,$modx->getOption('core_path').'components/simplecart/').'model/simplecart/', $scriptProperties);

to this:

$sc = $modx->getService('simplecart','SimpleCart',$modx->getOption('simplecart.core_path',null,$modx->getOption('core_path').'components/simplecart/').'model/simplecart/');

Note the removal of $scriptProperties as the fourth parameter. This same fix can be applied to the scCreateComment snippet which is also affected (but has a lower impact).

What happened? (Technical details ahead.)

SimpleCart relies on FormIt for handling of the checkout form, and creating an order when the customer chose their payment method is implemented as a FormIt hook, scCreateOrder.

In that snippet (hook), the SimpleCart service class is initialized, like so:

$sc = $modx->getService(
    'simplecart',
    'SimpleCart',
    $modx->getOption('simplecart.core_path',null,$modx->getOption('core_path').'components/simplecart/').'model/simplecart/',
    $scriptProperties
);

This is pretty standard code that anyone that has built an extra for MODX has likely written at some point.

The problem that 4th parameter, $scriptProperties. It allows passing in additional properties into the SimpleCart class (which arrive in the 2nd $config parameter in the constructor), which allows overriding the standard configuration.

$scriptProperties in a FormIt hook contains a lot of variables, varying from the useful $formit and $hook, to various configuration options and properties that were passed to the FormIt snippet call. Before FormIt 4.2, the $scriptProperties included configuration options in camelCase, like corePath and modelPath. In 4.2+, FormIt’s configuration changed to snake_case, like core_path and model_path.

SimpleCart also uses snake_case configuration keys (as of v2.4), and this change in FormIt 4.2 causes internal SimpleCart configuration to be overridden by FormIt configuration values. Most notably, the model_path changed from core/components/simplecart/model/ to core/components/formit/model/, and as a result of that, trying to load the xPDO model for SimpleCart no longer worked in the hook.

This leads to a whole bunch of errors like these:

[2019-02-27 19:25:03] (ERROR @core/xpdo/xpdo.class.php : 644) Could not load class: simpleCartCurrency from mysql.simplecartcurrency.
[2019-02-27 19:25:03] (ERROR @ core/xpdo/xpdo.class.php : 1655) Could not load class simpleCartCurrency!
[2019-02-27 19:25:03] (ERROR @ core/xpdo/xpdo.class.php : 644) Could not load class: simpleCartCurrency from mysql.simplecartcurrency.
[2019-02-27 19:25:03] (ERROR @ core/xpdo/xpdo.class.php : 762) simpleCartCurrency::load() is not a valid static method.
[2019-02-27 19:25:03] (ERROR @ core/xpdo/xpdo.class.php : 644) Could not load class: simpleCartMethod from mysql.simplecartmethod.
[2019-02-27 19:25:03] (ERROR @ core/xpdo/xpdo.class.php : 1655) Could not load class simpleCartMethod!
[2019-02-27 19:25:03] (ERROR @ core/xpdo/xpdo.class.php : 644) Could not load class: simpleCartMethod from mysql.simplecartmethod.
[2019-02-27 19:25:03] (ERROR @ core/xpdo/xpdo.class.php : 762) simpleCartMethod::load() is not a valid static method.

But, more importantly, the following fatal error (or a variation on it) would be triggered when trying to checkout and customers cannot pay for their order:

PHP Fatal error: Uncaught Error: Call to a member function set() on null in core/components/simplecart/controllers/web/Order.class.php:216

The fix is simple; removing $scriptProperties from the 4th parameter on getService in scCreateOrder. That prevents the configuration from being overridden, and allows models to be loaded to make sure everything works as expected.