Personal tools
Plone Registry Strikes Back

"A Useful Tool Registry Is"

Sep 18, 2012

Plone Registry Strikes Back

My journey exploring hidden features of the Plone registry continues. This time we will focus on aspects related to product migration, and how to get a nice user interface for our users

My last post was about how to use Plone registry in a clean way, also when storing complex data inside it.

Today we'll talk about the Plone registry again! I've some other tips to share!

Another good article

I'm not the only one to be inspired by the registry. After my first article about this subject, I came upon Complex Plone registry settings revisited. Take a read, is another interesting approach!

What's new?

I needed to implement the same product that inspired me for the last article, collective.analyticspanel, with some new features requested by a customer of ours.

Regardless the specific features, what is important is that:

  • it somehow changes the type of one of our existing field;
  • it adds a new field (that should be kept separated from the others).

 

Changing the field type

collective.analyticspanel 0.2It can be common problem: in previous version (0.2) of collective.analyticspanel the users were provided with a checkbox (boolean field) named "Apply to the whole subtree".

The customer asked to change the set of possible values from "True or False" to "True, False or False-with-exceptions".

The easiest way of doing it (the Dark Side) is to add a new boolean field (another checkbox). Considering that we were migrating from an old version, this suboptimal solution may indeed be used.

But we should ask ourselves: what kind of control we'd like to see, if we could develop the solution from scratch? For sure, a combobox (so: a Tuple of values).

collective.analyticspanel-0.3.0-04.pngI like the Light Side so, on version 0.3, I preferred to migrate old Boolean values to the new Tuple.

The way of migrating is to write some Python code during the product upgrade. This is much simpler than you can expect because in fact we are not really changing the field type, as long as we are changing the old name of the field, apply_to_subsection with the more appropriate apply_to.

Thus, we are copying the old (boolean) value to a new (non-boolean) field.

        ...
        for path_config in old_settings.path_specific_code:
            apply_to_subsection = path_config.apply_to_subsection
            del path_config.apply_to_subsection
            if apply_to_subsection:
                path_config.apply_to = u'subtree'
            else:
                path_config.apply_to = u'context'
        ...
Note that our fields are not basic registry elements, but sub-elements of path_config, one of the complex objects we played with in the previous article.

For a complete example see the whole migration code.

So we delete the old (Boolean) value, and translate the new value to a simple string (using the items from the vocabulary of the new combobox).

I want a new fieldset

Also the second task implied adding a new field.

Keeping an eye on the usability of the resulting interface, we saw that the form was becoming a little "chaotic" (I like simple forms, don't scare users if you can avoid it!). As the new field's default value is OK for 95% percent of product users, we know that the best choice was to move it into another "Advanced" fieldset.

Now the question is: how to add a fieldset in Plone registry? The only documentation I found is an article from Malthe Borch (the man who saved us all by releasing z3c.jbot): "Getting registry settings in Plone to display in fieldsets".

By following that article, I reached the target. How did it work for my needs?
Without registry settings, all fields belong to a "Default" fieldset (not visible in Plone inasmuch as it's the one and only fieldset).

To split fields into more that one fieldset, you need a combination of settings via control panel view and separate interfaces.
The general idea is to keep separate interfaces for every fieldset: in that case, the registry needs to use a new interface that inherits from both.

This is how interfaces looks like:

    class IAnalyticsSettings(Interface):
        """Settings used in the control panel for analyticspanel: general panel
        """
        ... your default fields

    ... 

    class IAnalyticsAdvancedSettings(Interface):
        """Settings used in the control panel for analyticspanel: advanced panel
        """
        ... your advanced field

    ... 

    class IAnalyticsSettingsSchema(IAnalyticsSettings, IAnalyticsAdvancedSettings):
        """Settings used in the control panel for analyticspanel: unified panel
        """

And this is how it's handled by control panel:

    class FormAdvanced(group.Group):
        label = _(u"Advanced settings")
        fields = field.Fields(IAnalyticsAdvancedSettings)

    class AnalyticsSettingsEditForm(controlpanel.RegistryEditForm):
        """Media settings form.
        """
        schema = IAnalyticsSettingsSchema
        fields = field.Fields(IAnalyticsSettings)
        groups = (FormAdvanced,)
        ... 

Another important change is in the Generic Setup registration: while the old version of the product was registering the IAnalyticsSettings interface, the new one must register the composed ones: IAnalyticsSettingsSchema (keep this information for later use).

<registry>
<records interface="collective.analyticspanel.interfaces.IAnalyticsSettingsSchema" />
</registry>

collective.analyticspanel-0.3.0-05.pngDone! The final result is quite agreeable!

Migration

Let say you are a version 0.2 user, then you migrate to version 0.3 but finally you want to remove the product. In that scenario I found a little issue related to our change of interface.

The old (0.2) uninstall procedure was like this:

<registry>
<record interface="collective.analyticspanel.interfaces.IAnalyticsSettings"
field="general_code"
delete="True"/>
<record interface="collective.analyticspanel.interfaces.IAnalyticsSettings"
field="error_specific_code"
delete="True"/>
<record interface="collective.analyticspanel.interfaces.IAnalyticsSettings"
field="path_specific_code"
delete="True"/>
</registry>

The new one (0.3) is this:

<registry>
<record interface="collective.analyticspanel.interfaces.IAnalyticsSettingsSchema"
field="general_code"
delete="True"/>
<record interface="collective.analyticspanel.interfaces.IAnalyticsSettingsSchema"
field="error_specific_code"
delete="True"/>
<record interface="collective.analyticspanel.interfaces.IAnalyticsSettingsSchema"
field="path_specific_code"
delete="True"/>
<record interface="collective.analyticspanel.interfaces.IAnalyticsSettingsSchema"
field="folderish_types"
delete="True"/>
</registry>

The weird effect of uninstalling 0.3 version of the product is that we still see in the general Plone registry the old values registered through version 0.2.

The solution is simple: during the product migration we shall also run a simple generic setup import step (we named it "clean_registry") that launches an uninstall procedure that cleans the registry from the values used in old version:

<registry>
<!-- those registry entries were used in version 0.2 and below -->
<record interface="collective.analyticspanel.interfaces.IAnalyticsSettings"
field="general_code"
delete="True"/>
<record interface="collective.analyticspanel.interfaces.IAnalyticsSettings"
field="error_specific_code"
delete="True"/>
<record interface="collective.analyticspanel.interfaces.IAnalyticsSettings"
field="path_specific_code"
delete="True"/>
</registry>

What about your beloved Plone 3 compatibility?

Ugly Plone 3 registryOnce again, this product is still compatible with Plone 3 but with limitations:

  • There's a bug in Plone 3 versions of plone.app.vocabulary so we can't use a combobox with a vocabulary in the Plone registry. So: on Plone 3 we are not using a combobox, but a simple textarea (user can't select values, but need to write them manually)
  • Fieldsets are not working: luckily you'll get no errors, but simply they are not displayed (and the final UI is really ugly!)

Conclusion

I hope that this article can help you to maintain order in the Plone registry!

Photos taken from emigepa

Filed under: , ,
comments powered by Disqus