skip to navigation
skip to content

dolmen.app.search 0.4

Catalog search utilities for Grok applications

Downloads ↓

dolmen.app.search provides components to search objects inside a Grok application.

Searchers

dolmen.app.search introduces a new component : the ISearcher. This component is dedicated in searching and returning a set of objects, using a search term.

The provided API is:

>>> from dolmen.app.search.interfaces import ISearchAPI
>>> interfaceDescription(ISearchAPI)
ISearcher: A component dedicated to search
ICatalogSearcher: A specialized ISearcher querying a catalog

Test environment

In order to test our searchers, we need an operationnal application with at least one index.

We prepare out imports:

>>> import grok
>>> from grok import index
>>> from zope.index.text.interfaces import ISearchableText
>>> from zope.interface import Interface
>>> from zope.schema import TextLine

We create a model that will be cataloged:

>>> class IRipper(Interface):
...   """A serial killer.
...   """
...   searchabletext = TextLine(title=u"Name of the ripper")

>>> class Ripper(grok.Model):
...   grok.implements(IRipper)
...
...   def __init__(self, searchabletext):
...     self.searchabletext = searchabletext

We create a Grok application, that will be out site manager:

>>> class Backstreet(grok.Container, grok.Application):
...   """A dark alley.
...   """

>>> grok.testing.grok_component('application', Backstreet)
True

We define an index that will be the base for our search:

>>> class RipperIndexes(grok.Indexes):
...  grok.site(Backstreet)
...  grok.context(IRipper)
...  searchabletext = index.Text()

>>> grok.testing.grok_component('indexes', RipperIndexes)
True

Now we persist our application and set it as the default site:

>>> from zope.site.hooks import setSite
>>> app = Backstreet()
>>> root = getRootFolder()
>>> root['berner_street'] = app

>>> setSite(app)

The Grok application has created the catalog:

>>> from zope.component import getUtility
>>> from zope.catalog.interfaces import ICatalog
>>> catalog = getUtility(ICatalog)
>>> catalog
<zope.catalog.catalog.Catalog object at ...>

Our index is there:

>>> catalog['searchabletext']
<zope.catalog.text.TextIndex object at ...>
>>> catalog['searchabletext'].documentCount()
0

Indexing

The catalog is ready. Now, if we create a content and persist it, the cataloging mechanism will do the work for us:

>>> jack = Ripper(u"Jack the knife")
>>> grok.notify(grok.ObjectCreatedEvent(jack))
>>> app['jack'] = jack

>>> catalog['searchabletext'].documentCount()
1

The searchabletext is set. That is what is cataloged in our site catalog:

>>> jack.searchabletext
u'Jack the knife'

Searching

An ISearcher can be used as an utility. dolmen.app.search provides a default implementation of an ICatalogSearcher. This component is used to query the site catalog:

>>> from dolmen.app.search import ICatalogSearcher
>>> searcher = getUtility(ICatalogSearcher, "searcher.sitecatalog")
>>> searcher
<dolmen.app.search.searchers.SiteCatalogSearcher object at ...>
>>> searcher.catalog == catalog
True

The search method of the ICatalogSearcher takes a search term and the name of the index. By default, it uses the searchabletext index:

>>> result = searcher.search(term="Jack")
>>> result
<dolmen.app.search.sets.PermissionAwareResultSet instance at ...>
>>> list(result)
[<dolmen.app.search.tests.Ripper object at ...>]

If we provide a non existing index name, an error is raised:

>>> result = searcher.search(term="Jack", index="non-existing")
Traceback (most recent call last):
...
ValueError: Index 'non-existing' does not exist

Wildcard

A wildcard can be given, when searching a text index:

>>> result = searcher.search("Ja")
>>> list(result)
[]

>>> result = searcher.search("Ja*")
>>> list(result)
[<dolmen.app.search.tests.Ripper object at ...>]

Permission

By default, our searcher checks the zope.View permission on the objects of the result set. We can provide another permission explicitly:

>>> result = searcher.search("knife", permission="i-do-not-exist")
>>> list(result)
[]

A grok.Permision class can be used instead of a string:

>>> from dolmen.app.security import CanViewContent
>>> result = searcher.search("knife", permission=CanViewContent)
>>> list(result)
[<dolmen.app.search.tests.Ripper object at ...>]

If permission is set to None, nothing is checked:

>>> result = searcher.search("knife", permission=None)
>>> list(result)
[<dolmen.app.search.tests.Ripper object at ...>]

View and viewlet

dolmen.app.search comes with two browser components. A search form viewlet and a result page.

Search viewlet

A search viewlet is registered to display a search form input. In order to test the output of the viewlet, we need a view:

>>> class GasLamp(grok.View):
...   """A view where the air's cold and damp
...   """
...   grok.context(IRipper)

>>> grok.testing.grok_component('view', GasLamp)
True

We get the view to render the viewlet:

>>> from zope.publisher.browser import TestRequest
>>> from zope.component import getMultiAdapter

>>> request = TestRequest()
>>> view = getMultiAdapter((jack, request), name="gaslamp")

The Search viewlet is registered for the dolmen.app.layout.Top manager. We construct this manager:

>>> from dolmen.app.layout import Top
>>> manager = Top(jack, request, view)

We can now call, update and render the Search viewlet:

>>> from dolmen.app.search.browser import Search
>>> search = Search(jack, request, view, manager)
>>> search.update()
>>> print search.render()
<form id="searchbox" method="post"
      action="http://127.0.0.1/berner_street/search.result">
  <input type="text" autocomplete="off" name="search_term"
         id="search-widget" value="" />
  <input type="submit" name="search_button"
         id="search-button" title="Search" alt="Search"
         value="Search" />
</form>

Result page

The viewlet posts the data to the search.result view. This view fetches the search_term from the request, queries the ICatalogSearcher and displays the results:

>>> request = TestRequest(form = {'search_term': 'jack'})
>>> results = getMultiAdapter((jack, request), name="search.result")
>>> results
<dolmen.app.search.browser.Results object at ...>

>>> results.update()
>>> print results.content()
<div class="search-result">
  <div class="search-header">
    <h1>Search</h1>
    <h3>Found 1 results for jack</h3>
  </div>
  <dl class="search-results content-listing">
    <dt>
      <a href="http://127.0.0.1/berner_street/jack"
         title="jack">
        <span>jack</span>
      </a>
    </dt>
  </dl>
</div>

Changelog

0.4 (2010-11-05)

  • The package now works for Grok 1.2.
  • The icon is now using the "icon" and no longer "contenttype_icon" view.
  • The dependencies have been reviewed and slimmed down.

0.3.1 (2010-07-24)

  • 0.3 release was broken because of missing locales directory.

0.3 (2010-07-24)

  • Added French translation.

0.2.2 (2009-01-08)

  • Declare all dependencies and some cleanup.
  • Require dolmen.content.View permission for Search viewlet.

0.2.1 (2009-12-01)

  • Removed all imports from zope.app.* for intid and catalog. Using now the new packages. This makes dolmen.app.search compatible with grok1.1a2.

0.2 (2009-12-01)

  • Modified the imports to make it compatible with grok 1.1 (ztk 1.0)

0.1 (2009-11-08)

  • Initial release
 
File Type Py Version Uploaded on Size # downloads
dolmen.app.search-0.4.tar.gz (md5) Source 2010-11-05 9KB 344