Skip to content
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

Updating interface aware records with field node but without interface results in error #40

Open
Nachtalb opened this issue Jul 29, 2020 · 0 comments

Comments

@Nachtalb
Copy link

Tested with Plone=5.1.6 with plone.app.registry=1.7.5 and plone.registry=1.1.5


Problem

In the release 1.1.0 and 1.1.1 ftw.datepicker added registry entries as
follows:

<record interface="ftw.datepicker.interfaces.IDatetimeRegistry" field="formats">
    <value purge="false">
        <element key="de">d.m.Y H:i</element>
        <element key="fr">d/m/Y H:i</element>
    </value>
</record>

Like this, the created record in the registry has a field knows about
the interface (due to the interface="..."). If a field knows about the
interface the record will provide IInterfaceAwareRecord on
initialization
.

In version 1.2.0 the record declaration was changed to:

<record name="ftw.datepicker.interfaces.IDatetimeRegistry.formats">
    <field type="plone.registry.field.Dict">
        <title>The formats per language</title>
        <key_type type="plone.registry.field.TextLine" />
        <value_type type="plone.registry.field.TextLine" />
    </field>
    <value purge="false">
        <element key="de">d.m.Y H:i</element>
        <element key="fr">d/m/Y H:i</element>
    </value>
</record>

In here we do not define the interface anymore but do define the field
itself.

Now when you have initially installed version 1.1.0 or 1.1.1 the field
knows the interface. When you reinstall the profile with version 1.2.0
and above plone.app.registry will get the existing record from the
registry. At that moment it sees that its field knows about the
interface and thus provides the IInterfaceAwareRecord interface. During
the registration of the entry, it finds that we declare the field
manually in the XML. Because of that, it creates a new field in case
something has changed. During this creation process of the field, it lets
the field know about the interface
. BUT because we didn't define an
interface this time in the record (interface="...") it sets None
instead of our actual interface.

Now during the rest of the installation process, the record provides
IInterfaceAwareRecord even though the field does not know about the
interface anymore.

Later on, in the record registration process, this will trigger the
redispatchInterfaceAwareRecordEvents subscriber from plone.registry.
At that moment it thinks, the record knows about the interface because it
still provides IInterfaceAwareRecord. This causes a failure when trying
to resolve that interface.


Expected behaviour

According to the plone.app.registrys docs<record name="ftw.datepicker.interfaces.IDatetimeRegistry.formats"> and <record interface="ftw.datepicker.interfaces.IDatetimeRegistry" field="formats"> are equivalent so it should fail when using one method once and the other another time.


Proposed Solution

Remove the interface by extending this if:

if field is not None and not IFieldRef.providedBy(field):
# Set interface name and fieldName, if applicable
field.interfaceName = interfaceName
field.fieldName = fieldName

like so:

if field is not None and not IFieldRef.providedBy(field):
    # Set interface name and fieldName, if applicable
    field.interfaceName = interfaceName
    field.fieldName = fieldName

    if interfaceName is None and existing_record:
        # Remove interface awareness in case the previous field was interface aware
        noLongerProvides(existing_record, IInterfaceAwareRecord)

Or we set the old interfaceName to the new field like so:

if field is not None and not IFieldRef.providedBy(field):
    # Set interface name and fieldName, if applicable
    field.interfaceName = existing_record.field.interfaceName if existing_record else interfaceName
    field.fieldName = fieldName

In the second solution, the fieldName could also be reused from the old field if possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant