The stock portal_catalog lets you search database by a number of basic properties,
like id, uid, portal_type, title, description, validation_state, creation_date
and many more. Sometimes, however, you may need to add you own properties to it -
if you want to be able to quickly search on a property that you defined, or if
you need your custom property to be a sortable and searchable column in a
listbox powered by portal_catalog.
Table of Contents
This is how to achieve this - let's take an example: we need to be able to quickly
find an email address, and figure out to whom it belongs. Email adress is stored
in a property "url_string" of a portal_type "Email". We can search for it like this:
result=[r.getObject() for r in context.portal_catalog(portal_type='Email')]
adrs=[o for o in result if o.getUrlString()=='firstname.lastname@example.org']
But we don't want to do it, because it would give very poor perfomance.
The sql catalog is there to make things fast, let's use it.
For searching, this is it - if you insert into the 'email' table uid and url_string
of an existing email address, portal_catalog will be able to find it. What we still
need to do is to make sure the table is created and cleared when necessary, and
that our email addresses catalog themselves automatically.
CREATE TABLE `email` (
`uid` BIGINT UNSIGNED NOT NULL,
PRIMARY KEY `uid` (`uid`),
KEY `url_string` (`url_string`)
) TYPE = InnoDB;
DROP TABLE IF EXISTS email;
Make portal_catalog record url_string upon reindexing
When you call a 'reindexObject' method on an ERP5 object, you actually tell
portal_catalog to execute all z_ methods defined in the erp5_mysql catalog
and selected in the 'sql_catalog_object_list' box. So: Create a ZSQL method
arguments: uid, getUrlString, getPortalType
<dtml-in prefix="loop" expr="_.range(_.len(uid))">
<dtml-if expr="_.len(email_list) > 0">
email (`uid`, `url_string`)
<dtml-in prefix="loop" expr="email_list">
<dtml-sqlvar expr="uid[loop_item]" type="int">,
<dtml-sqlvar expr="getUrlString[loop_item]" type="string" optional>
The tricky part here is that your method is executed every time you catalog
anything, so it has to check whether the object is actually and Email address,
otherwise it would raise an error. So it filters the list of objects to be
catalogged, and, if any are found, puts them into the email table. Add it to
the selection in 'sql_catalog_object_list' box. Create a ZSQL method
DELETE FROM email WHERE <dtml-sqltest uid op=eq type=int>
Add it to the selection in 'sql_uncatalog_object' box.
Voila - you're done. Now you can search and sort on it in a listbox exactly as
you do on title, id or description, and search for it like this:
If you had some emails in your database before, don't forget to reindex them!
Also, keep in mind that catalog propeties are cached, so all this may not work
until you clear the cache (in portal_caches tool, or using erp5admin Firefox extension).