Does anyone have any suggestions of bringing saveddata count to another part of a Plone site using collective.easyform

Hello,

I have been tasked with grabbing the count of form submissions in a easyform item and displaying it on another page in a plone site.

I have tried getting to it with a page template. I can get all the easyform forms listed but can't seem to get to the save adapter.

Doesn't seem to be doable with a page template or easyform custom script adapter.

If anyone has any guidance that would be awesome. Thanks for reading this.

Rob

From digging through the https://github.com/collective/collective.easyform code I got the impression you can get to the saved data (a save data adapter with the ID save_data) via something like this:

from collective.easyform.api import get_actions
saver = get_actions(easyform)['save_data']
count = len(saver.field.itemsSaved())

but you can't use that import statement in an EasyForm custom script adapter (or any RestrictedPython script).

In the test code, I saw that something like this could work, but it can't be done in TAL either (publishTraverse is a no-no):

view = easyform.restrictedTraverse('@@actions')
view2 = view.publishTraverse(view.request, 'save_data')
count =  len(view2.field.itemsSaved())

This seems heavy handed, but a browser view can do this:

<browser:page
    for="collective.easyform.interfaces.IEasyForm"
    layer="..interfaces.IEasyFormLayer"
    name="count_saved_data"
    class=".view.CountSavedDataView"
    permission="zope2.View"
    />

class CountSavedDataView(BrowserView):

    def __call__(self):
        """return total count of all save data rows"""
        from collective.easyform.api import get_actions
        from collective.easyform.interfaces import ISaveData
        count = 0
        self.context = EasyFormForm(self.context, self.request)
        form = self.context.context
        for action_id in get_actions(form):
            action = get_actions(form)[action_id]
            if ISaveData.providedBy(action):
                count += action.itemsSaved()
        return "%s saved item%s" % (count, "s" if count != 1 else "")

Visiting http://localhost:8080/Plone/myform/@@count_saved_data would return

1 saved item
1 Like

It's heavy handed but it is what I would do.
Or go all the way and extend easyform to support this out of the box.

I'd feel sheeping adding just that specific view to collective.easyform, but if I were to add something to the add-on, a more generally useful view would be better. It is surprising to me that the save data adapters would be so difficult to access. Maybe a view that returns all the actions, and another view that returns the values of a specific save data adapter?

OK, adding this view:

<browser:page
    for="collective.easyform.interfaces.IEasyForm"
    layer="..interfaces.IEasyFormLayer"
    name="get_save_data_adapters"
    class=".view.GetSaveDataAdaptersView"
    permission="zope2.View"
    />


class GetSaveDataAdaptersView(BrowserView):

    def __call__(self, *args, **kwargs):
        """return all contained save data adapters"""
        from collective.easyform.api import get_actions
        from collective.easyform.interfaces import ISaveData
        self.context = EasyFormForm(self.context, self.request)
        form = self.context.context
        adapters = []
        for action_id in get_actions(form):
            action = get_actions(form)[action_id]
            if ISaveData.providedBy(action):
                adapters.append(action)
        return adapters

you can define a page template that iterates over the form's save data adapters and obtains a count of their items:

<html>
  <head>
    <title tal:content="template/title">The title</title>
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
  </head>
  <body>
    
    The form with ID <span tal:content="here/id">[form id]</span> contains the following save data adapters:

    <ul>
        <div tal:define="adapters here/get_save_data_adapters" tal:repeat="adapter adapters">
        
            <li>
                <span tal:content="adapter/getName">ID</span>: <span tal:content="adapter/itemsSaved">[item count]</span> items
            </li>
        
        </div>
    </ul>

  </body>
</html>

It outputs this:

The form with ID ff1 contains the following save data adapters:

  • save_data: 2 items

I added this ticket. I think I might go ahead and make a PR for it.

The new view @@get_save_data_adapters has been merged into master and has been released as 2.0.0b6, with (minimal) docs:

1 Like

Thank you Kim. You rock! I got this to work.

1 Like