Using Filtering

by Russ Ferriday last modified Feb 07, 2010 01:19 AM
Describe how to define new filters for your own content.

Using Filtering

Description:

Describes how to define new filters for your own content.

As you now know all about Z3 adapters, you might want to use our interfaces to define new filters. And walk through your hierarchy.

To begin with, take a quick look at the interesting interface IFilterFolder which is in Products.ATContentTypes.interface.folder.IFilterFolder. This interface says what you have to define to create a correct filter:

    class IFilterFolder(Interface):

        def listObjects():
            """
              return the list of filtered object without looking at security
            """

        def listPermittedObjects():
            """
              return the list of filtered object and looking at security
            """

        def filter(context):
            """
              filter the objects in the context to be walked by TreeWalker.
              This method is private and shouldnt be called from outside.
              Use listObjects() instead
            """

I won't give more comment about this interface, it describes itself.

Now let's have a look at Products.ATContentTypes.adapters.folder, there you find the Filter class :

        class Filter(object):
            def __init__(self, context):
                """
                  context should be a folderish object
                """
                self.context = context

            def listObjects(self):

                """
                    return the list of filtered object without looking at security                    
                """
                return self.filter()

            def listPermittedObjects(self):
                """
                   return the list of filtered object taking care of security
                """
                return LazyFilter(self.filter(), skip='')

            def filter(self):
                """
                    filter the objects in the context to be walked by TreeWalker.
                """
                raise NotImplementedError, 'This method should be overriden in a subclass'

            def __call__(self):
                return self.listPermittedObjects()

As you see this class nearly implements IFilterFolder. By nearly I mean that there is just one method that isn't clearly implemented, the filter method. So the only thing you need to do to create a new filter is to implement this method and inherit from the Filter class. Let's do it!

Let's say that we want all documents in the folder which are in the workflow state "published":

        >>> from Products.ATContentTypes.adapters.folder import Filter
        >>> from Products.ATContentTypes.interface.folder import IFilterFolder
        >>> from Products.CMFCore.utils import getToolByName
        >>> class FilterPublishedDocument(Filter):
        ...     """
        ...         Just takes the published documents in folder
        ...     """
        ...     implements(IFilterFolder)
        ...
        ...     def filter(self):
        ...         workflow = getToolByName(self.context, 'portal_workflow')
        ...         publishedDocuments = []
        ...         for document in self.context.objectValues('Document'):
        ...             if(workflow.getInfoFor(document,'review_state') == 'published'):
        ...                 publishedDocument.append(document)
        ...
        ...         return publishedDocuments

And that's all for filtering. If you want to use it inside the treeWalker you should link this filter to the folderish object you want to walk on (should be ATFolder), or just give the FilterPublishedDocument class as parameter to TreeWalker initialization.

To use FilterPublishedDocument for ATFolder the zcml would look like this like this:

        <adapter
            for="Products.ATContentTypes.interface.IATFolder"
            factory="Products.ATContentTypes.adapters.folder.FilterPublishedDocument"
            provides="Products.ATContentTypes.interface.IFilterFolder"
            />

Note that we could have used the catalog in the filter to filter the objects in a defined state (this might have been a bit quicker - but less simple).