Bookmark and Share
Document Actions

Comprendere il portal_catalog

Up one level
(al più presto disponibile)

Avete visto come cercare contenuti in Plone, ma ora vedremo nel dettaglio come avviene la categorizzazione sottostante e la ricerca di contenuti. Lo strumento portal_catalog immagazzina tutte queste informazioni che sono leggermente diverse ed estese rispetto alla versione dello strumento Zcatalog. Trovate un eccellente riferimento online per il Zcatalog su http://zope.org/Documentation/Books/ZopeBook/2_6Edition/SearchingZCatalog.stx.

Il catalogo offre tre elementi chiave per un sito Plone:

  • crea indici relativi ai contenuti

  • contiene i metadati riguardanti il contenuto nell'indice

  • offre un'interfaccia di ricerca per esaminare velocemente il contenuto del vostro sito Plone.

Tra tutti i differenti oggetti presenti nel vostro sito Zope, solo gli oggetti con un  tipo di contenuto sono catalogati. Gli oggetti Zope, gli strumenti e altri oggetti non sono inseriti nel catalogo. Per questa ragione, lo strumento catalogo è strettamente collegato ai tipi di contenuto e al loro uso. Potete accedere al catalogo attraverso lo strumento portal_catalog nella ZMI.

Nota: quando un catalogo restituisce un risultato, non restituisce l'oggetto; restituisce invece i metadati salvati nel catalogo. Questi metadati sono una serie di campi o colonne per ogni valore dell'oggetto.

Indicizzare il contenuto

La prima parte del lavoro del catalogo è quello di costruire gli indici del contenuto. Un indice offre soprattutto un metodo per cercare velocemente e in modo efficace un contenuto. Per questa ragione, il contenuto dell'indice non è costruito per essere chiaro o avere un senso; è costruito invece per essere veloce ed efficiente nella ricerca. Quando cercate all'interno di un sito Plone, cercate gli indici e il catalogo vi restituisce i risultati che corrispondono alla vostra richiesta.

Un indice richiede un oggetto Plone con un valore, un metodo o un attributo particolari e poi indicizza qualsiasi cosa l'oggetto restituisca per quella richiesta. Come effettivamente venga creato l'indice del contenuto dipende dai tipi di indice. I principali tipi di indici sono i seguenti:

  • DateIndex: costruito per elencare le date e vi permette di effettuare ricerche basate sulle date e sul tempo

  • DateIndexRange: questo indice è utile nel caso abbiate due date, come la data di inizio e quella di fine, e volete eseguire più ricerche entro quelle due date.

  • KeywordIndex: questo restituisce un risultato in base a qualsiasi parola chiave corrisponda alla richiesta. È ideale per cercare argomenti o parole chiave sugli oggetti

  • ZCTextIndex: questo indice fornisce capacità di ricerca efficienti su parti di testo. Supporta un grande numero di caratteristiche, che discuteremo nel dettaglio più avanti.

Potete vedere quali indici sono definiti in un catalogo cliccando portal_catalog e selezionando il tab "Indexes". Questo vi darà una lista di tutti gli indici definiti nel vostro sito Plone. Le colonne sono: il nome dell'indice, il tipo, il numero di oggetti e quando è stato modificato l'ultima volta.

Se non siete sicuro dei contenuti di un indice, allora potete vedere i contenuti degli indici nella ZMI. Cliccate su portal_catalog e selezionate Catalog per vedere un elenco completo di tutti gli oggetti catalogati. Cliccate su un oggetto e si aprirà una finestra con i contenuti dell'indice e dei metadati. I metadati appaiono per primi quindi scorrete in basso per vedere gli indici.

Per aggiungere, rimuovere o modificare gli indici ritornate al tab "Indexes. Usate il solito box Add per inserire un nuovo indice o per rimuoverne uno. Se volete eseguire una  reindicizzazione, allora selezionate gli indici sulla sinistra e cliccate su Reindex Se aggiungete un indice al catalogo, questo sarà vuoto, ciò significa che dovete cliccare su Reindex e assicurarvi che ci sia del contenuto nel vostro indice.

Nota: se avete un sito di grandi dimensioni, questo processo di indicizzazione può essere lungo e intenso per il processore, perciò dovreste evitare di eseguirlo nei momenti di congestione del sito.

Come viene indicizzato un oggetto

I tipi di contenuto vengono indicizzati automaticamente perché derivano da una classe chiamata PortalContent, che a sua volta deriva da una classe mix-in chiamata CMFCatalogAware. La classe CMFCatalogAware gestisce tutto il codice per assicurarvi che quando aggiungete, modificate, copiate, cancellate o rinominate un oggetto, il catalogo e il workflow rimangano aggiornati.

Essenzialmente l'oggetto viene passato al catalogo e viene richiesta l'istruzione appropriata (indicizza, rimuovi dall'indice e così via). Il catalogo scorre poi ogni indice e per ognuno richiede gli attributi o i metodi dell'oggetto stesso. Per molti indici, l'attributo o il metodo ricercati hanno lo stesso nome dell'indice. Ad esempio, per l'indice Titolo, il CMFCatalogAware cercherà un attributo o un metodo chiamato Titolo e riempirà l'indice con il risultato e ripeterà il processo con ogni colonna dei metadati.

Due eccezioni in questo processo sono il FieldIndex e il TopicIndex. Quando aggiungete un FieldIndex, potete specificare che quell'indice esamini un diverso valore rispetto al nome. Per esempio potreste creare un indice con l'ID getVersion, che prende in considerazione il valore di versione.

Come vedremo più avanti, alcuni indici hanno dei vantaggi rispetto ad altri, perciò può essere utile avere due diversi indici che tengano conto dello stesso valore.

TopicIndex è un diverso tipo di indice costruito su una serie di insiemi nello stesso momento nel quale il contenuto viene indicizzato. Se volete eseguire più ricerche con multiple condizioni, allora non potete fare richieste con le normali ricerche di catalogo. Per esempio, se volete cercare solo immagini che hanno un titolo superiore ai 30 caratteri, allora potete  aggiungere una ricerca per o.portal_type == 'Image' and len(o.Title()) > 30 . Per fare ciò dovete creare un TopicIndex e poi cliccarci sopra dal tab Indici; potete anche aggiungere espressioni multiple per costruire un indice. In questo momento i TopicIndex non vengono usati da nessuna parte in Plone.

Cercare o attraversare le directory per cercare gli oggetti dal ZODB è un processo lento e poco efficiente. Come vedremo in questo capitolo è meglio usare lo strumento portal_catalog, richiedere uno o più indici e recuperare una lista di piccoli oggetti chiamati "brain” (cfr. sezione “Utilizzare i risultati di ricerca” in questo capitolo).

Come reindicizzare tutto il contenuto nel vostro sito Plone

La classe mix-in CMFCatalogAware offre anche due metodi utili per reindicizzare un particolare oggetto: reindexObject e reindexObjectSecurity. Con reindexObject potete aggiornare tutti gli indici senza nessun parametro o passare una lista di indici che necessita di essere aggiornata. Il metodo reindexObjectSecurity invece aggiorna gli indici relativi alla sicurezza per l'oggetto in questione.

Se avete effettuato un gran numero di modifiche a livello codice, inserito un nuovo prodotto o rinominato o spostato il vostro oggetto radice di Plone, potreste aver bisogno di reindicizzare tutto il contenuto del vostro sito. Nella ZMI cliccate su portal_catalog, poi su Advanced e poi su Update catalog. Verrà eseguito il processo di aggiornamento del catalogo.

Attenzione: questo processo è ancora più intenso per il processore che reindicizzare un solo indice e puoi richiedere molto tempo e può utilizzare molta memoria e potenza di calcolo se avete un database di grandi dimensioni.

Cercare nel catalogo

Ovviamente il quesito principale è come cercare nel catalogo e usare i risultati. La prima di queste operazioni dipende dagli indici, perciò analizzeremo ogni indice e mostreremo come effettuare le ricerche. La seconda operazione comprende la manipolazione dei risultati, perciò vi mostreremo come fare.

Tutti i seguenti esempi sono in Python perché è il miglior modo di cercare in un catalogo. Vi mostreremo anche un veloce esempio di come agganciare Python ad un template. Vi raccomandiamo vivamente di usare Python per manipolare il catalogo perché è realmente il modo migliore per farlo; vi permette la maggiore flessibilità senza preoccuparvi della sintassi.

In generale, la ricerca avviene utilizzando il metodo searchResults in portal_catalog e passandogli una serie di parametri a parole chiave. Un paio di parole chiave sono riservate ma le restanti vengono mappate direttamente agli indici con lo stesso nome.

Perciò se volete cercare l'indice "SearchableText" potrete usare un  parametro con lo stesso nome (keyword parmeter di python). Le parole chiave riservate sono le seguenti:

  • sort_on: questo è l'indice che ordina i risultati, presupponendo che l'indice vi permetta l'ordine (gli indici di testo non permettono l'ordine)

  • sort_order: questa vi permette di ordinare in modo crescente o decrescente un certo parametro; se non è specificato, l'ordine di default è crescente

  • sort_limit: con questa potete effettuare l'ordine leggermente più veloce; vi verrà restituito solo il numero di elementi che volete.

Perciò una ricerca generica per i primi cinque elementi pubblicati ordinati per data, avrà più o meno questo aspetto:

context.portal_catalog.searchResults(
review_state = "published",
sort_order = "reverse",
sort_limit = 5,
sort_on="Date"
)

La ricerca restituirà l'intersezione dei risultati dell'indice, così questo troverà i primi cinque elementi pubblicati, in ordine di data decrescente. Potete effettuare ricerche che sono l'unione di risultati; potete ottenere multipli risultati e poi combinarli insieme, ma questo è un caso raro.

Se eseguite una ricerca senza parametri, allora l'intero contenuto del catalogo viene restituito. Di default, tutte le ricerche aggiungono i valori per le date di inizio e fine assicurandovi di visualizzare solo il contenuto tra queste due date, a meno che l'utente che effettua la richiesta non abbia il permesso “Access inactive portal content”.

Cercare nell'indice Field o Date Index

Per effettuare ricerche in un indice "FieldIndex", basta passare come argomento il valore del campo. Ogni voce che corrisponde verrà restituita; per esempio, per cercare tutte le immagini in un sito, usate la seguente istruzione:

results = context.portal_catalog.searchResults(


Type = "Image"


)

Un FieldIndex può riguardare anche una gamma di oggetti, e l'indice tenterà di trovare tutti i valori che stanno in mezzo per eseguire una comparazione di valori. Questa gamma può essere tra due date, due numeri o due sequenze; dipende realmente dal valore del FieldIndex. Potete effettuare questa ricerca attraverso un dizionario nell'indice, invece di una semplice sequenza. Il dizionario dovrebbe contenere due valori: un elenco chiamato query, che contiene i valori da testare, e un intervallo che definisce una serie di valori. Un intervallo è una sequenza di uno dei seguenti valori:

  • min: qualsiasi cosa che sia più grande dell'elemento più piccolo

  • max: qualsiasi cosa che sia più piccolo dell'elemento più grande

  • minmax: qualsiasi cosa che sia la più grande e maggiore dell'elemento più piccolo

Ad esempio, per trovare tutti gli eventi che hanno una data di termine maggiore di ora (in altre parole qualsiasi cosa accada nel futuro), usate la seguente istruzione:

from Products.CMFCore.utils import getToolByName
from DateTime import DateTime
portal_catalog = getToolByName(context, 'portal_catalog')
now = DateTime()
results = portal_catalog.searchResults(
Type = "Event"
end = { "query": [now,],
"range": "min" }
)

Per cercare in un intervallo, come ad esempio tutte le notizie di Dicembre, avete bisogno di calcolare le date di inizio e fine per il mese. Da queste date, potete costruire la seguente richiesta:

start = DateTime('2009/12/01')
end = DateTime('2009/12/31')
results = portal_catalog.searchResults(
Type = "News Item",
created = { "query": [start, end],
"range": "minmax" }
)

I DateIndex lavorano nello stesso modo dei FieldIndex, e spesso si sostiuiscono a vicenda.

Cercare nel keyword index

Di default, un indice KeywordIndex restituisce tutti i valori che corrispondono. L'unico KeywordIndex in Plone è "subject", che corrisponde alle parole chiave che l'utente ha assegnato ad un oggetto attraverso il tab Proprietà nell'interfaccia Plone. Per cercare tutti gli elementi con la parola chiave Africa, usate la seguente istruzione:

results = context.portal_catalog.searchResults(
Subject = "Africa"
)

Come per il FieldIndex, l'indice KeywordIndex ammette query più complicate con diversi oggetti e operatori booleani and/or (“or” è selezionato di default). Questo vi permette di trovare tutti gli oggetti che hanno ogni combinazione di parole chiave. Per trovare tutti gli oggetti che hanno come soggetto "Africa" e "sole", usate la seguente istruzione:

results = context.portal_catalog.searchResults(
Subject = { "query": ["Africa", "sun"],
"operator": "and" }
)

Cercare nel PathIndex

Un indice pathIndex vi permette di cercare tutti gli oggetti in un determinato percorso Restituisce ogni oggetto sotto una determinata cartella, perciò se richiedete tutti gli oggetti sotto la cartella "Membri", vi restituirà tutto ciò che c'è nelle home directory di ognuno. Per esempio:

results = context.portal_catalog.searchResults(
path = "/Plone/Members"
)

Se volete restringere ancora di più la ricerca, potete utilizzare un parametro "livello. Questo è un numero che rappresenta la posizione dell'oggetto nel percorso, da sinistra quando lo scomponi con gli slash. Per esempio, nel codice visto in precedenza, Plone ha un livello 0, Member ha livello 1, e così via. Come per il KeywordIndex, potete  utilizzare degli operatori booleani and/or. Per ottenere tutti gli oggetti della cartella /Plone/Members/danae e della cartella /Plone/testing/danae usate la seguente istruzione:

results = context.portal_catalog.searchResults(
path = { "query": ["danae"],
"level" : 2 }
)

Cercare nel ZCTextIndex

Questo indice è il più complicato e richiede tutta una serie di opzioni. Ognuna di queste opzioni richiede un lessico; fortunatamente Plone crea e configura tutto in automatico.

Se cliccate su portal_catalog, selezionate il tab Contents, e cliccate su plone_lexicon, potete vedere la configurazione di default del lessico. Cliccando il tab Query vi verranno mostrate tutte le parole che ci sono nel lessico costruite dai contenuti del tuo sito Plone.

Le ricerche nel ZCTextIndex vengono effettuate usando il formato che abbiamo descritto parlando della funzionalità di ricerca del portale. Richiede una sintassi per la ricerca come quella che usate con Google o con altri motori di ricerca. Potete cercare qualsiasi termine come:

results = context.portal_catalog.searchResults(
SearchableText = "space"
)

Come già visto potete anche cercare usando i seguenti comandi:

  • Caratteri jolly: potete usare un asterisco che ha il significato di un qualsiasi numero di  lettere. Per esempio, inserendo Giorn* corrisponde sia a Giorno che a Giorni. Non potete usare un asterisco all'inizio della parola

  • Caratteri singoli: potete usare un punto interrogativo ovunque che significa una singola lettera. Ad esempio inserendo ca?o corrisponde a caso, caro, capo, e così via. Non potete usare il punto interrogativo all'inizio di una parola

  • 'and': potete usare la congiunzione “and” che significa che entrambi i termini devono esistere. Ad esempio inserendo Roma and Martedì vi ritornerà un risultato con entrambe le parole nel contenuto.

  • 'or': potete usare la parola “or” che significa che uno dei due termini esiste. Per esempio inserendo Roma or Martedì vi verrà restituito un risultato dove solo una delle due parole è nel contenuto.

  • Not: potete usare la parola “not” per ricevere un risultato dove la parola non sia presente; potete inserire anche “and” come prefisso. Per esempio inserendo "benvenuto and not pagina" il risultato mostrerà le pagine che contengono benvenuto, ma non pagina

  • Frasi: sono gruppi di parole tra virgolette che significano che più parole devono apparire in sequenza. Per esempio inserendo “pagina di benvenuto” corrisponderà al risultato “Questa pagina di benvenuto è usata per introdurre il CMS Plone”, ma non un risultato che contiene solo Benvenuto.

  • -frase: potete specificare una frase con il prefisso (-). Per esempio inserendo benvenuto -“pagina di benvenuto” corrisponderanno tutte le pagine contenenti Benvenuto ma nessuna che contiene la frase “pagina di benvenuto”.

  • Usare i risultati della ricerca

    Una volta che ottenete i risultati cosa potete farci? La prima cosa che molte persone fanno è guardare il risultato e scoprire che si tratta di un elenco di oggetti che sono stati catalogati. Bene, non è così; o meglio si tratta di una serie di oggetti "brain" catalogati. Questi oggetti "brain" sono degli oggetti che contengono le colonne di metadati viste prima. Potete accedere ad ognuna di queste colonne come se fossero degli attributi. Per esempio, per stampare tutti gli ID dei risultati, usate il seguente comando:

    results = context.portal_catalog.searchResults()
    for result in results:
    print result.getId
    return printed

    In questo esempio, getID corrisponde ad una colonna di metadati, così verrà visualizzato il valore del metadato getID che il catalogo contiene per quell'oggetto.

    Se cercate di accedere a un valore (metadato) che non esiste allora vi verrà restituita un'eccezione AttributeError. Di seguito alcuni metodi disponibili in un brain:

  • getPath: restituisce fisicamente il path di questo oggetto dentro a Zope

  • getURL: restituisce l'URL di questo oggetto modificato opportunamente in base alla configurazione del virtual host

  • getObject: restituisce l'oggetto al quale fa riferimento

  • getRID: restituisce l'ID univoco per l'oggetto all'interno del catalogo, questo ID cambia ogni volta che l'oggetto viene tolto dal catalogo. È solo per uso interno

Se volete ottenere l'oggetto per ogni risultato, potete fare come vedremo nel prossimo esempio. Tuttavia, c'è una ragione per cui il catalogo non esegue questa azione: è costoso (in termini di elaborazione) perché riguarda l'estrazione di un oggetto dal database (e di tutti gli oggetti in mezzo fino all'oggetto radice) e l'esecuzione di molti controlli relativi alla sicurezza. Se potete, cercate di fare in modo che i metadati contengano le giuste informazioni, in questo modo avrete un'applicazione molto più rapida. Ovviamente, i metadati a volte non possono contenere tutto, ma è importante considerare questa opzione. Per estrarre ogni oggetto, usate le seguenti istruzioni:

results = context.portal_catalog.searchResults()
for result in results:
object = result.getObject()
print object
return printed

Dal momento che avete un lista Python di questi "brain", potete semplicemente manipolare i risultati nella maniera che vi sembra più utile. Per scoprire quanti risultati vengono restituiti, potete semplicemente usare la funzione "len" in questo modo:

results = context.portal_catalog.searchResults()
print "Number of results", len(results)
return printed

Per ottenere solo i primi dieci elementi, fate così:

results = context.portal_catalog.searchResults()
return results[:10]

Per filtrare ulteriormente potete usare un ciclo:

results = context.portal_catalog.searchResults()
for result in results[:10]:
# Title returns a string so we can use the find method of
# a string to look for occurrence of a word
if result.Title.find("Plone") > -1:
print result.Title
return printed

Per ottenere un oggetto a caso nel catalogo, usate il modulo random:

import random
results = context.portal_catalog.searchResults()
r = random.choice(results)
object = r.getObject()
return object

Legare tutto insieme: fare una form di ricerca

Nel precedente paragrafo vi abbiamo mostrato come ottenere alcuni risultati dal catalogo e come usare oggetti "Script (Python)" per visualizzare i risultati. Ma vi starete probabilmente chiedendo, come poter fare la stessa cosa da un template?

Ora parleremo del sistema di template che viene comunemente usato in Plone: Zope Page Templates (ZPT). Esso genera sempre un XHTML valido e vi consente di creare pagine web dinamiche per le applicazioni web di Zope. ZPT usa il Template Attribute Language (TAL) che consiste nell'utilizzo di speciali attributi xml. Ma il TAL non è argomento di questo capitolo; ne parleremo più avanti; per maggiori dettagli su ZPT potete consultare il Zope Book (http://www.zope.org/Documentation/Books/ZopeBook/2_6Edition/ZPT.stx).

Supponete di avere i risultati da una query del catalogo e che possiate utilizzare tal:repeat per mettere insieme i risultati uno alla volta. E' proprio in questo modo che vengono messe insieme molte portlet; sia le portlet degli elementi pubblicati che  degli eventi eseguono delle query e poi mostrano i risultati.

Quelle portlet includono la query in una pagina template chiamandola direttamente:

<div tal:define="results python:➥
here.portal_catalog.searchResults(portal_type="Event")">

Oppure chiamando un oggetto "script (Python)" separato che restituisce i risultati. Per esempio, lo script di seguito è chiamato getCatalogResults:

##parameters=
kw = {}
# enter your query into the kw dictionary
return context.portal_catalog(**kw)

In una pagina template, otterrete i risultati nel seguente modo:

<div tal:define="results here/getCatalogResults">

Dopo aver fatto ciò, dovete mettere i risultati insieme usando l'istruzione tal:repeat. Così potete accedere ad ogni colonna di metadati direttamente nel template (con TAL) utilizzando un'espressione di percorso (path expression). Potete ottenere il metadato "Title"  richiamando result/Title. Il seguente codice è un esempio di template che fa un ciclo sui brain restituiti da getCatalogResults e mostra ogni elemento all'interno di un elenco non ordinato:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"
lang="en-US"
metal:use-macro="here/main_template/macros/master"
i18n:domain="plone">
<body>
<div metal:fill-slot="main">
<ul tal:define="results here/getCatalogResults">
<li tal:repeat="result results">
<a href=""
tal:attributes="href
result/getURL"
tal:content="result/Title"/>
<span
tal:replace="result/Description" />
</li>
</ul>
</div>
</body>
</html>

Una caratteristica del metodo searchResults è che se non viene passato nessun  parametro alla funzione, il metodo li cercherà nella richiesta. In questo modo se volete permettere a un form di postare dei parametri sui quali poi basare la ricerca, allora tutto ciò che dovete fare è cambiare la precedente searchResults con la seguente:

<ul tal:define="
results python: here.portal_catalog.searchResults(REQUEST=request)
">

Ora potete rieseguire la vostra query e aggiungere qualsiasi indice all'URL. Per esempio, se chiamate questa pagina template testResults e ci aggiungete ?Type=Document alla fine dell'URL nel vostro browser, appariranno solo i documenti nel vostro sito. Il seguente è un form per chiamare la vostra pagina template:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"
lang="en-US"
metal:use-macro="here/main_template/macros/master"
i18n:domain="plone">
<body>
<div
metal:fill-slot="main">
<p>Select
a tipi di contenuto to search for</p>
<form
method="post" action="testResults">
<select name="Type">
<option
tal:repeat="value
python:here.portal_catalog.uniqueValuesFor('portal_type')"
tal:content="value" />
</select>
<br
/>
<input type="submit" class="context">
</form>
</div>
</body>
</html>

Questo script usa un metodo chiamato uniqueValuesFor nel catalogo, che restituisce tutti i valori univoci che esistono per un indice. Questo vi permette di fare cose come inserire un piccolo menu a tendina in un form, che può essere piuttosto utile.

Nota: dal momento in cui, in quasi tutte le richieste dovete passare dei parametri, potete impostare un form di ricerca che potrebbe passare questa informazione attraverso il modulo di ricerca. Questo è quello che le pagine di ricerca e ricerca avanzata fanno. Per esempio, noterete che andando su un sito Plone e carcate “birra” nel box di ricerca, sull'URL apparirà Searchable-Text=birra.

A questo punto, il fatto di rendere le pagine tanto complicate quanto volete diventa un esercizio di HTML e template. Ovviamente, il miglior posto dove cercare esempi sono i template delle portlet di Plone. Tutte le portlet con le quali avete già confidenza in Plone (come il calendario, gli eventi, i collegamenti, e così via) sono costruite usando le query di catalogo per determinare cosa devono visualizzare.

Avvantaggiarsi della ZCA: ricercando per interfacce

Come vedrete in seguito nei prossimi capitoli, Plone può avvantaggiarsi della Zope Component Architecture. Uno dei concetti principali della ZCA sono le interfacce. Le interfacce sono qualcosa di simile ai contratti; un'interfaccia può essere usata per contrassegnare un oggetto (marker interface) o per dirvi se l'oggetto "promette" di avere alcune funzioni descritte nella stessa interfaccia.

Gli oggetti possono fornire una o più interfacce, ma … perché stiamo parlando di interfacce ora? Perché questa informazione è indicizzata dallo strumento portal_catalog dentro l'indice (keyword index) "object_provides". In questo modo è possibile guadagnare flessibilità e sbarazzarsi delle query del catalogo sui "portal_type" e usare l'indice object_provides con un'interfaccia più generica (questo sarà più chiaro nell'esempio che stiamo per spiegare).

Immaginiamo un caso comune. Molte volte le query di catalogo sono costruite con "portal_type", ma cosa succede se volete rimpiazzare un componente con uno differente per ottenere un'implementazione migliore e più veloce? O se volete che entrambe le tipologie di oggetti esistano nella tua applicazione? Di norma, dovreste modificare tutte le query di catalogo nel codice Python; il codice che ne risulta non potrebbe essere riutilizzato e non sarebbe generico. Ma usando invece la ZCA, non vi verrà richiesto di modificare per niente un codice già esistente (e ben funzionante!).

Per fare un esempio più specifico, immaginate un'applicazione di valutazione per un sito web di e-learning. Gli utenti accedono ed effettuano l'esame. Quando un utente invia le sue risposte, i risultati vengono immagazzinati in un oggetto di tipo Result  nello stesso oggetto di valutazione. Gli oggetti del Result forniscono l'interfaccia IResult e questo oggetto può essere usato per memorizzare i risultati, comparando diversi risultati per la valutazione dell'esame, compilando statistiche, e così via. Dopo un paio di mesi, il sito ha già molti utenti e sottoscrizioni agli esami, ma potreste avere bisogno di un nuovo oggetto di risultato che non sia un oggetto a se stante ma che sia capace invece di contenere altri oggetti, come in una cartella (nel gergo Plone lo chiamiamo oggetto “folderish”), per esempio perché avete bisogno di gestire gli allegati con un workflow particolare e alcune caratteristiche extra collegate a quel workflow.

La soluzione in questo caso è abbastanza semplice. Avete solo bisogno di creare un nuovo Result  folderish che vi fornirà la stessa interfaccia IResult; ad esempio, il tipo ResultFolder . In questo modo ResultFolder promette di comportarsi nello stesso modo in cui è descritto nell'interfaccia IResult; altri componenti dell'applicazione già sanno come comportarsi con questo oggetto perché esso ha lo stesso comportamento dei vecchi Result type. Dopo aver scritto questo nuovo componente, i risultati appena creati saranno di tipo ResultFolder. Potete ottenere tutto ciò senza fare nessuna modifica nel codice esistente, in più potete usare e comparare gli oggetti del nuovo e del vecchio tipo!

E per quanto riguarda le portlet utente e le interfacce di ricerca per i risultati basati sulle query di catalogo? Nessuna modifica è necessaria per il codice già esistente, testato e ben funzionante!

Come è possibile? E' possibile in quanto tutte le query di catalogo sono basate sull'indice object_provides invece che sull'indice portal_type, tutte le query di catalogo cercheranno gli oggetti che offrono il marcatore Iresult nella loro interfaccia. Non importa se il nuovo tipo di risultati ha un diverso portal_type.

Le query di catalogo fatte da interfacce sono simili a ciò che segue:

from Products.CMFCore.utils import getToolByName
from Products.Quiz.interfaces import IResult
portal_catalog = getToolByName(context, 'portal_catalog')
results = portal_catalog.searchResults(object_provides=[IResult.__identifier__,])
return results

Di base, invece di cercare il portal_type, usiamo le interfacce che vi permettono di guadagnare flessibilità. Se le query del catalogo esistenti sono simili alle precedenti, non sono necessarie modifiche al vostro codice!

Il codice Python del precedente esempio restituisce un'elenco di tutti gli oggetti brain nell'intero portale, e ogni singolo oggetto brain in quell'elenco corrisponde a un oggetto che fornisce l'interfaccia Iresult. Come mostrato in questo capitolo, probabilmente vorrete filtrare i risultati per creatore o stato di revisione.

Nota: se provate ad usare il precedente codice, esso non funzionerà. IResult non può essere importato perché il pacchetto Quiz non esiste; è solo un esempio!

Infine, di seguito un reale esempio preso da plone/portlet/collection/collection.py:

class ICollectionPortlet(IPortletDataProvider):
"""A
portlet which renders the results of a collection object.
"""
...
target_collection
= schema.Choice(title=_(u"Target collection"),➥
description=_(u"Find the collection which provides➥
items to list"),required=True, source=SearchableTextSource➥
Binder({'object_provides' :
IATTopic.__identifier__},➥
default_query='path:'))
...

Il sorgente della target_collection è costruito usando una query dell'indice object_provides. Così, se create un nuovo tipo che eredita dal ATTopic e fornisce la stessa interfaccia del IATTopic, questa portlet funzionerà anche con il nuovo tipo, senza nessuna modifica.

by Dario Pollino last modified 2010-03-15 14:20
Contributors: Maurizio Delmonte, Davide Moro, Alice Narduzzo, Fabrizio Reale, Enrico Barra, Andrea Cannizzaro, Andrea D'Este, Maurizio Lupo, Giuseppe Masili, Dario Pollino, Matteo Sorba.