Sugar and older versions of PHP

The latest version of PHP that Sugar 6.5 supported was PHP 5.3 which was released back in 2009. That is a long time ago folks. A sizable portion of the Sugar Developer community was in grade school back when PHP 5.3 was cool.

While we like to keep Sugar on the cutting edge, we have not been able to keep up to date with the latest PHP release. We have needed to maintain an upgrade path in each new Sugar release for customers still on Sugar 6.5. That is, up until now.

PHP Support matrix

As of Sugar 7.7.1 release:

Sugar version

Supported PHP versions

6.5.x

5.2

5.3

7.6.x

5.3

5.4

7.7.0

5.3

5.4

5.5

7.7.1

5.3

5.4

5.5

5.6

We do not plan on supporting 4 different versions of PHP forever, so you can expect to see support for older versions of PHP, such as PHP 5.3, to be dropped in upcoming Sugar releases.

Here are some suggested settings for using Zend OPcache with Sugar instances from the Performance team. These settings are a good starting point then you can optimize based on your individual instance's needs.

Just add the following to your php.ini file.

; Suggested OPcache settings for Sugar

opcache.max_accelerated_files = 10000

opcache.memory_consumption = 256

opcache.fast_shutdown = 1

opcache.interned_strings_buffer = 16

Ultimately, utilizing the built-in PHP accelerator helps reduces the amount of work necessary to deploy and maintain a Sugar supported stack with accelerated PHP.

Long Term Support until the end of 2018

The community support windows for older versions of PHP have been expiring. But Long Term Support for PHP 5.6 ends in December 2018. So PHP 5.6 in production environments is a safe bet for the long haul.

Upgrading our Backbone

Have you done some Sidecar programming lately? Then you have been using Backbone. Backbone is the err... backbone of Sidecar. It provides all the base MVC classes which are extended by Sidecar to create the Sugar 7 UI. For example, all Sidecar controllers (Views, Layouts, Fields) extend from the Backbone View class.

Ultimately, a solid background in Backbone programming will turn you into a Sidecar wizard in no time.

But if you are a Backbone aficionado then you might have noticed that Sugar 7.7 and earlier versions uses an old version of Backbone (specifically Backbone 0.9.10). We have been missing out on bug fixes and miscellaneous feature improvements. So for Sugar 7.8 we will be moving to Backbone 1.2.3. Since Backbone.js has a hard dependency on Underscore.js, we will also upgrade the Underscore library from 1.4.4 to 1.8.3.All Sugar Developers should check out the Backbone changelog and the Underscore changelog to see if their code customizations could be impacted by this long overdue library upgrade.

Read on to learn more about some adjustments you need to make to your Sugar code.

Changes to Sidecar controller DOM event delegation

Views now always delegate their events in setElement. You can no longer modify the events hash or your view's el property in initialize.

This means that modifying this.events in the initialize() function of a Backbone View to register DOM event handlers is no longer supported by Backbone. This is because DOM events set in the events hash (this.events) are delegated before initialize() is even called. However, since this was a common practice for Sugar code and customizations we have altered the default Backbone behavior within Sidecar for the Sugar 7.8 release.Sugar will continue to continue to call delegateEvents() during initialize() in Sugar 7.8 for compatibility but the practice is deprecated since Backbone no longer supports it. Sidecar controllers that modify this.events during initialize() will continue to work until this workaround is removed in an upcoming Sugar release.

Here is a simple example of a Sidecar view that uses this deprecated practice.

A simple example

./custom/clients/base/views/example/example.js

[code language="javascript"]

/** This approach is deprecated in Sugar 7.8 release **/

({

events: {...},

initialize: function(options) {

if (...) {

this.events['click'] = function(e){...};

}

this._super('initialize', [options]);

},

...

})

This will not work in a future Sugar release.

A Record View use case

Let's examine a common Sidecar customization use case.

Say we need to extend the out of the box Sugar RecordView controller to launch a wizard user interface on a mouse click.

We plan to listen for a special DOM click event but we also do not want to break any existing Record view event listeners.

To implement this feature, Sugar Developers commonly used code such as the following:./custom/..../clients/base/views/record/record.js

[code language="javascript"]

/** This approach is deprecated in Sugar 7.8 release **/

({

extendsFrom: 'RecordView',

initialize: function(options) {

// Extending the RecordView events in a deprecated fashion

this.events = _.extend({}, this.events, {

'click .wizard': '_launchWizard'

});

this._super('initialize', [options]);

},

_launchWizard: function(){

// ... do something ...

}

})

To reiterate, the examples above will no longer work in a future Sugar release. Sugar Developers should update any similar code to use alternative approaches listed below.

Event Delegation Alternatives

Here are some alternatives that you can use for delegating DOM events with your Sidecar controllers.

Statically define your events hash

Define your events all within the events object hash. Note that when extending controllers that this would override any events defined on a parent controller.

[code language="javascript"]

({

events: {

'mousedown .title': 'edit',

'click .button': 'save',

'click .open': function(e) { ... }

}

...

})

Use a callback function for dynamic events

You can assign the events variable of Backbone controllers a function instead of an object hash. This function will then be used to determine the event hash used when delegateEvents() is called by Backbone.

[code language="javascript"]

({

events: function(){

if (...) {

return {'click .one': function(){...}};

} else {

return {'click .two': function(){...}};

}

}

...

})

If you must, then call delegateEvents() function directly

You can optionally pass an alternative event hash using this.delegateEvents(events). When unspecified, this.events is used by default. The delegateEvents() function removes any previously delegated events at same time so it is safe to call multiple times.

[code language="javascript"]

({

extendsFrom: 'RecordView',

oneEvents: {...},

twoEvents: {...},

isOne = true,

toggleOneTwo: function(){

if (this.isOne) {

this.delegateEvents(_.extend({}, this.events, this.oneEvents));

} else {

this.delegateEvents(_.extend({}, this.events, this.twoEvents));

}

this.isOne = !this.isOne;

}

...

})

Other important Backbone changes

Backbone.js no longer attaches options to the Backbone.View instance by default (as of 1.2.0). Sugar Developers should know we plan to deprecate this.options on Sidecar controllers in a future Sugar release.

This upgrade may also break customizations of Sidecar routes that expect URL parameters to be concatenated to the first argument passed to the Backbone router's callback. Sugar Developers should change the signature of their router callbacks to specify the additional argument for URL parameters.

For example:Old way:

[code language="javascript"]

// in a sugar7.js equivalent file

{

name: 'search',

route: 'search(/)(:termAndParams)',

callback: function(termAndParams) {

// termAndParams => "?module=Accounts&foo=bar"

// commence ugly URL parsing...

}

}

New way:

[code language="javascript"]

// in a sugar7.js equivalent file

{

name: 'search',

route: 'search(/)(:term)',

callback: function(term, urlParams) {

// term => "this is a search term"

// urlParams => "module=Accounts&foo=bar"

// no more ugly URL parsing!

}

}

Potential Breaking Change: Sugar customizations that override the sync method on any instances of Backbone.Model and Backbone.Collection should should be updated to match Backbone's new signatures for the internal success/error callbacks for Model#fetch, Model#destroy, Model#save, and Collection#fetch methods.

Potential Breaking Change: The method signature for error callbacks for Model#fetch, Model#destroy, Model#save, and Collection#fetch has changed. The Backbone.Model or Backbone.Collection is passed as the first parameter and the second parameter is now the HttpError XHR object.

For example:Old way:

[code language="javascript"]

this.model.save({}, {

error: function(error) {

...

}

});

New Way:

[code language="javascript"]

this.model.save({}, {

error: (model, error) {

...

}

});

Potential Breaking Change: Sugar customizations that set the id property directly on a Backbone.Model will not work with Backbone Collections. Sugar Developers should always use Backbone's internal APIs/methods, meaning they should be using model.set('id', ...) instead.