Package: dolmen.app.search
dolmen.app.searchprovides components to search objects inside a
Grok application.Searchersdolmen.app.searchintroduces 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 catalogTest environmentIn 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 TextLineWe 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 = searchabletextWe 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)
TrueWe 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)
TrueNow 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()
0IndexingThe 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()
1The searchabletext is set. That is what is cataloged in our site catalog:>>> jack.searchabletext
u'Jack the knife'SearchingAn ISearcher can be used as an utility.dolmen.app.searchprovides 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
TrueThe search method of the ICatalogSearcher takes a search term and the
name of the index. By default, it uses thesearchabletextindex:>>> 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 existWildcardA 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 ...>]PermissionBy default, our searcher checks thezope.Viewpermission on the
objects of the result set. We can provide another permission
explicitly:>>> result = searcher.search("knife", permission="i-do-not-exist")
>>> list(result)
[]Agrok.Permisionclass 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 viewletdolmen.app.searchcomes with two browser components. A search form
viewlet and a result page.Search viewletA 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)
TrueWe 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")TheSearchviewlet is registered for thedolmen.app.layout.Topmanager. 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 pageThe viewlet posts the data to thesearch.resultview. This view
fetches thesearch_termfrom 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>Changelog0.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