Personal tools
You are here: Home Plone Book 11. Inhaltstypen manipulieren und kategorisieren
Die maximale Bildbreite kann wie folgt gewählt werden:

11. Inhaltstypen manipulieren und kategorisieren

Document Actions

Inhaltstypen manipulieren und kategorisieren

In diesem Buch habe ich Ihnen gezeigt, wie Sie Inhalte zu Ihrer Site hinzufügen können, und ich habe die in Plone enthaltenen Inhaltstypen wie Dokumente, Bilder usw. beschrieben. Bisher waren Sie allerdings auf genau diese Inhaltstypen eingeschränkt und auf solche, die Sie in Produkten aus dem Internet gefunden haben. Der mächtigste Teil von Plone, die Manipulation dieser Inhaltstypen, bildet das Hauptthema dieses Kapitels.

In diesem Kapitel vergleiche ich die verschiedenen Objekttypen in Plone miteinander. Dadurch erhalten Sie einen Einblick in manche Entwicklungstaktiken für Ihre eigenen Projekte. Dann behandle ich Inhaltstypen und zeige, wie sie in Plone registriert werden. Diese Registrierung bildet die Basis für die Anpassung der Typen an das von Ihnen gewünschte Format. Anschließend fahre ich mit der Kategorisierung von bzw. der Suche in Inhalten fort - Aufgaben, von denen Sie sicher wissen möchten, wie man sie ausführt. Mit diesem Wissen werden Sie wichtige Entscheidungen darüber treffen können, wie Sie Ihre Site entwickeln und neue Inhaltstypen erstellen können.

Lassen Sie mich jetzt also Ihren Appetit auf die Manipulation von Inhaltstypen wecken. Sobald Sie einen völlig neuen Inhaltstyp anpassen können, können Ihre Benutzer fast alles erstellen und bearbeiten, was Sie nur möchten! Zum Beispiel:

  • Benutzer können ein Bild einer Zellkultur hochladen, das mit gewissen Bildbearbeitungsbibliotheken zerschnitten und manipuliert wird und dann dem Benutzer in einem bestimmten Format präsentiert wird.
  • Benutzer können eine MP3-Audiodatei hochladen, daraus den Titel und Künstlernamen extrahieren und sie in Plone platzieren.
  • Sie können einen vollständigen E-Commerce-Shop erstellen, in dem Plone-Benutzer Elemente wie z.B. Kleidungsstücke zum Verkauf anbieten, mit Informationen zu Versandkosten, Größe und Garantie.
  • Benutzer können ein Microsoft Word-Dokument hochladen und dann so manipulieren, dass gewisse Teile davon ausradiert werden. Benutzer mit einer niedrigen Sicherheitsstufe können dann nur die Dokumente mit ausradierten Passagen sehen.

All diese Möglichkeiten und noch mehr stehen Ihnen in Plone zur Verfügung! Es gibt wirklich nur wenige Einschränkungen. Aus diesem Grund ist Plone wahrscheinlich eines der erweiterbarsten und flexibelsten Frameworks, die verfügbar sind. Die einzige wirkliche Einschränkung liegt in Ihrer Fähigkeit, in Python zu programmieren (oder darin, sich jemanden zu leisten, der es in Ihrem Auftrag macht).

In diesem Kapitel behandle ich daher Inhaltstypen im Detail, und dazu zählt auch, wie man sie über das Web registriert und manipuliert. Für die folgenden Abschnitte wird zwar kein Wissen über Python explizit verausgesetzt, aber ich empfehle Ihnen dennoch, sich wenigstens damit vertraut zu machen. Dieses Kapitel enthält auch Informationen über Formulare und darüber, wie man sie validiert.

Wenn Sie eigene Inhaltstypen entwickeln möchten, sollten Sie dieses Kapitel unbedingt lesen, unabhängig davon, ob Sie über das Web oder in Python entwickeln, denn dieses Kapitel behandelt die Bereiche, die man kennen muss, um die Registrierung von Inhaltstypen zu verstehen.

Das nächste Kapitel setzt diese Reise dann fort und bringt Ihnen die wirklich blutigen Details bei der Entwicklung von Inhaltstypen mit Python näher. Danach werden Sie Archetypes verwenden, um das Gleiche mit einem Zehntel an Aufwand zu machen. Mit Archetypes werden Sie dann einige wirklich coole und abgefahrene Sachen machen. Aber jetzt geht es zuerst einmal direkt zu Inhaltstypen!

Übersicht zu Inhaltstypen

Ich muss gestehen, ich habe in diesem Buch gewisse Begriffe verwendet, die ich nur oberflächlich erklärt habe. Daher wird es jetzt Zeit, das nachzuholen, damit Sie diese besser verstehen können. Folgende Konzepte sind von Bedeutung:

  • Inhaltstyp (Content Type): Das ist eine Art von Inhalt, der in einer Plone-Site registriert ist. Normalerweise, wenn auch nicht immer, ist ein Inhaltstyp etwas, das mit Hilfe der Plone-Schnittstelle von Benutzern einer bestimmten Sicherheitsstufe hinzugefügt und bearbeitet werden kann. Es wird empfohlen, in Plone Inhaltstypen wie Dokumente, Dateien und Bilder voneinander zu trennen. Diese Trennung von Inhalten in verschiedene Typen ist ein grundlegendes Konzept in Plone.
  • Element und Objekt: Diese Begriffe beziehen sich auf die eigentliche Instanz von irgendetwas. Es sind sehr überladene Begriffe, d.h., ihre Definition ist normalerweise stark kontextabhängig. Bisher habe ich in diesem Buch diese Begriffe bei einer bestimmten Instanz eines Inhaltstyps benutzt, z.B. bei einem bestimmten Dokument oder Bild. Von nun an werde ich den spezifischen Begriff, nämlich Inhaltstyp verwenden, wenn es um Inhaltstypen geht.
  • Werkzeug (Tool): Ein Werkzeug ist ein Dienst, der in einer Plone-Site vorhanden ist. Auf jeder Plone-Site kann es nur eine Instanz eines Werkzeugs geben. Ein Werkzeug macht von sich aus gar nichts, und externe Benutzer der Anwendung werden nie mitbekommen, wie viele Werkzeuge vorhanden sind oder was sie machen. Aber Inhaltstypen oder Anfragen von Benutzern interagieren mit den Werkzeugen. Einige wichtige Werkzeuge haben Sie bereits gesehen, z.B. portal_workflow, portal_skins und portal_actions.
  • Zope-Objekt: Das ist ein Objekt, das in Zope lebt. Es bietet den Benutzern eine bestimmte Funktionalität, und man kann über das ZMI (Zope Management Interface) darauf zugreifen. Aber es ist nichts, worauf Plone selbst zugreifen oder was es steuern würde. Wenn Sie zu einer Plone-Site gehen und auf das ZMI zugreifen, werden Sie eine große Anzahl von Objekten im ZMI sehen. Ein Werkzeug ist ein solches Objekt, die Plone-Site ist ein anderes, und die Cache-Manager sind weitere. Zwischen diesen Objekten gibt es eine Menge an Überlappungen. Plone enthält z.B. einen Inhaltstyp für Bilder und Zope verfügt über ein Bildobjekt. Beide haben ähnliche Aufgaben und funktionieren auf ähnliche Weise, aber Plone kann nur auf eines zugreifen.

Hinweis

Obwohl alles in einer Plone-Site in der Zope-Objektdatenbank (ZODB) ein Zope-Objekt ist, benutze ich diesen Begriff, um Objekte zu beschreiben, die keine Werkzeuge oder Instanzen eines Inhaltstyps sind.

Wann man Inhaltstypen erstellen sollte

Also gut, Sie bauen in Plone Ihre Superanwendung, die Ihnen Ruhm und Ehre und noch dazu ein sicheres Einkommen einbringen wird. Wie werden Sie sie aber strukturieren, und was bauen Sie überhaupt? Nun, das hängt davon ab, was Sie machen wollen, und davon, wie Sie ihre Entwicklung bisher eingeteilt haben. Die folgenden Fragen helfen Ihnen möglicherweise bei der Entscheidung:

  • Ändern Sie einfach nur Skins und einfache Verhalten, z.B. Portlets? Sie können in einer Skin fast alles machen, was Sie wollen, außer ein Werkzeug oder einen Inhaltstyp schreiben. Wenn Sie wirklich wollen, können Sie alle Cascading Stylesheets (CSS), Templates und Skripten ändern, die in einer Plone-Site enthalten sind.
  • Werden Mitglieder Ihrer Site mehrere Kopien eines Elements hinzufügen? Wenn ja, dann möchten Sie wahrscheinlich einen Inhaltstyp dafür schreiben.
  • Ist das ein Dienst, den andere Inhaltstypen benutzen könnten? Wenn ja, dann möchten Sie wahrscheinlich ein Werkzeug schreiben.
  • Möchten Sie mehrere Kopien von etwas, wollen aber nicht, dass es Mitglieder Ihrer Site erstellen und bearbeiten können? Wenn ja, dann möchten Sie wahrscheinlich ein Zope-Objekt. Aber Sie sollten noch einmal genau darüber nachdenken, was Sie machen.

Normalerweise wird eine Anwendung in mehrere Teile aufgeteilt: ein bis zwei Werkzeuge und ein oder zwei Inhaltstypen. Kapitel 12 behandelt die Erstellung eines Inhaltstyps, der einen Source Code, z.B. einen Python-Schnipsel, nimmt und die Syntax des Codes hervorhebt. Falls Sie diese Syntax-Hervorhebung an anderen Stellen brauchen können, dann könnten Sie sie in ein Werkzeug verwandeln, das von mehreren Inhaltstypen verwendet werden kann. Werkzeuge sind, kurz gesagt, die beste Art, um Funktionalität zu einer Site statt zu einem bestimmten Inhaltstyp hinzuzufügen.

Die Definition der Erstellung eines Inhaltstyps wird normalerweise von den Anforderungen der Benutzer diktiert, die diese Objekte hinzufügen, bearbeiten und steuern müssen. Es kann verlockend sein, mit der Erstellung eines Inhaltstyps für jede Art von Objekt zu beginnen, aber wie bei jeder Art von Entwicklung müssen Sie vorsichtig sein. Wäre es möglich, einen statt zwei Inhaltstypen mit minimalen Unterschieden zu benutzen? Das Wissen darüber, wie man so etwas konfiguriert, kommt mit zunehmender Erfahrung, aber die folgenden paar Kapitel werden bestimmt eine Hilfe sein.

Inhaltstypen konfigurieren

Nun enthält Ihre Plone-Site also Inhaltstypen, aber woher weiß die Plone-Site, wie diese konfiguriert werden? Die Antwort lautet, dass Attribute, Methoden, Sicherheit und Skins für alle Inhaltstypen im Dateisystem in Python und im entsprechenden Code definiert werden. Diese Information genügt Plone, um zu wissen, wie das Produkt benutzt wird. Wie Sie gesehen haben, ist die einzige Ausnahme hiervon der Workflow, der normalerweise außerhalb des Inhaltstyps definiert wird. Manche Produkte haben ihren eigenen Workflow, der als Verhalten zum Inhaltstyp hinzugefügt wird.

In Kapitel 10 habe ich gezeigt, wie Inhaltstypen in zwei Schritten in Plone installiert werden: Zuerst wird das Produkt in Zope installiert, dann wird der Inhaltstyp in jeder Plone-Instanz installiert. Beim zweiten Schritt werden Angaben über den Inhaltstyp installiert, die aus dem Dateisystem stammen und dann in Ihrer Plone-Site installiert werden.

Warum besteht dieser Vorgang aus zwei Phasen? In der zweiten Phase wird eine lokale Kopie des Produkts in Ihrer Plone-Site angelegt, und nun können Sie ändern, wie sich der Inhalt bei Ihnen verhält. Möchten Sie, dass ein Dokumentobjekt andere Reiter oben hat? Oder soll ein Dokumentobjekt anders manipuliert werden, anders aussehen oder sogar völlig anders benannt werden? Kein Problem! Nun können Sie Ihre Plone-Instanz über das Web ändern.

Dieser Ansatz ist der gleiche wie bei portal_skins, in dem Sie eine Skin in Ihrer lokalen Instanz anpassen können. Wenn es im Produkt zu Änderungen kommt und Sie eine neue Version von Plone installieren, betreffen diese Änderungen das Dateisystem. Aber nun können Sie diese Änderungen herunterladen und installieren. Weil Sie die Angaben in Ihrer Datenbank gemacht haben, behalten Sie diese angepasste Version.

Jeder Inhaltstyp in Plone verfügt über eine Einstellung im Werkzeug portal_types. Auch wenn jeder Inhaltstyp nur eine Einstellung im Werkzeug portal_types hat, kann es zu diesem Typ eine unbeschränkte Anzahl von Objekten in Ihrer Datenbank geben. Die Konfiguration wird bei Bedarf zu Rate gezogen, d.h., wenn Sie die Konfiguration ändern, aktualisieren Sie alle Objekte dieses Typs in der Datenbank.

Registrierung von Inhaltstypen im Werkzeug portal_types

Gehen Sie im ZMI zum Werkzeug portal_types, um auf die Registrierungsinformation zuzugreifen. Dort erhalten Sie eine Liste aller in dieser Plone-Site registrierten Inhaltstypen. Die meisten davon sind als etwas zu erkennen, das Sie mit wenigen Ausnahmen über die Plone-Schnittstelle hinzufügen könnten, z.B. Plone Site, TempFolder usw.

Jedes dieser Objekte ist eine Instanz mit Angaben zum Factory-Typ, was der Name eines bestimmten Konfigurationstyps ist. Klicken Sie auf ein beliebiges dieser Objekte, um auf die Typinformation zuzugreifen. Wenn Sie z.B. ein Ereignis anklicken, erhalten Sie eine lokale Kopie der Information zu dem Inhaltstyp. Über das Web können Sie Ihre Konfiguration ändern. In diesem Formular gibt es folgende Einträge:

  • Title: Der Titel des Inhaltstyps.
  • Description: Die Beschreibung, die zu diesem Inhaltstyp erscheint. Diese wird benutzt, wenn Sie zu den Ordnerinhalten gehen und Neuen Artikel hinzufügen anklicken, ohne einen Inhaltstyp anzugeben. Dann erscheint eine Liste aller Inhaltstypen und ihrer Beschreibungen.
  • Icon: Die ID des Icons, das für diesen Inhaltstyp benutzt wird.
  • Product metatype: Der Metatyp für diesen Inhaltstyp. Dieser bildet den Plone-Inhaltstyp auf den Zope-Metatyp ab.
  • Product name: Der Name des Produkts, in dem dieser Metatyp definiert ist.
  • Product factory method: Die Methode, die von der Produkt-Factory aufgerufen wird, um diesen Inhalt zu erstellen.
  • Initial view name: Wird in Plone nicht benutzt.
  • Implicitly addable: Gibt an, ob dieser Inhalt zu Plone hinzugefügt werden kann. Wenn dieser Eintrag ausgewählt ist, kann der Inhalt hinzugefügt werden, außer es ist explizit etwas anderes angegeben.
  • Filter content types: Falls dieser Inhaltstyp ein Ordner ist, aktivieren Sie das, um die Inhaltstypen zu filtern, die von Benutzern zu diesem Objekt hinzugefügt werden können.
  • Allowed content types: Falls dieser Inhaltstyp andere Elemente enthalten kann und Filter content types aktiviert ist, sind nur die in dieser Liste angegebenen Inhaltstypen erlaubt.
  • Allow discussion: Setzt den voreingestellten Status für Diskussionen bei allen Inhaltstypen. Falls dieser Eintrag aktiviert ist, können Benutzer den Inhalt diskutieren. Welche Benutzer das tun können, hängt von dem Recht Discuss content ab.

Nun werden Sie sich einige Aspekte dieser Registrierungsangaben detaillierter anschauen, wobei ich auch einige Beispiele zeige.

Wie ändert man das Icon eines Inhaltsyps?

Wenn Sie z.B. das Icon nicht mögen, das bei einem Inhaltstyp erscheint, müssen Sie lediglich ein neues Bild hochladen und sicherstellen, dass der Wert für das Icon im zuvor beschriebenen Formular gesetzt ist. Icons funktionieren am besten, wenn sie einen transparenten Hintergrund haben und 16 mal 16 Pixel groß sind.

Klicken Sie auf portal_skins und custom, und fügen Sie dann ein neues Bild hinzu. Im Werkzeug portal_types setzen Sie dann den Wert für das Icon auf den Wert der ID des hochgeladenen Objekts. Um zu testen, ob das Icon sich verändert hat, gehen Sie zur Plone-Schnittstelle und schauen sich dort um, wo das Objekt erscheinen könnte. Führen Sie z.B. eine Suche durch, oder sehen Sie im Formular zur Erstellung von Inhalten nach.

Aktionen

Wenn Sie sich die Konfiguration von Inhaltstypen in portal_types anschauen, sehen Sie einen Actions-Reiter. Diese Aktionen können auf den Inhaltstyp angewendet werden. Aktionen haben Sie schon kurz in Kapitel 4 gesehen, das eine detaillierte Liste dessen enthält, was unter diesem Actions-Reiter vorkommt.

Erinnern Sie sich daran, dass eine Aktion die Möglichkeit bietet, eine Liste von Angaben zu speichern, die leicht bearbeitet und auf die dann unter verschiedenen Bedingungen zugegriffen werden kann. Im Plone-Portal werden Aktionen oben auf den Seiten mit blauen Reitern dargestellt. Zu jedem Inhaltstyp erscheinen die Aktionen als grüne Reiter in der Seitenmitte.

Wie Sie gesehen haben, werden Aktionen in Werkzeugobjekten gespeichert. Viele Werkzeuge enthalten Aktionen, aber es gibt keine gute Möglichkeit, den Ort einer Aktion in Erfahrung zu bringen. Wenn Sie auf Ihrer Plone-Site eine bestimmte Aktion ändern möchten, müssen Sie zuerst das entsprechende Werkzeug finden, in dem sie gespeichert ist.

Sobald Sie diese Aktion gefunden haben, können Sie sie nach Belieben anpassen. Wenn Sie z.B. eine neue Aktion als grünen Reiter zu einem Dokument hinzufügen möchten, müssen Sie zunächst den richtigen Ort finden. Zu Glück sind die folgenden Tipps recht hilfreich beim Finden von Aktionen:

  • Wenn Sie eine Aktion zu einem Stück Inhalt suchen, z.B. Anzeigen oder Bearbeiten, dann befindet sie sich im entsprechenden Inhaltstyp im Werkzeug portal_types.
  • Wenn Sie nach einer Site-Aktion suchen, finden Sie sie im Werkzeug portal_action.
  • Sollten Sie die Aktion immer noch nicht finden, sehen Sie in einem verwandten Werkzeug nach. So befinden sich z.B. Registrierung und Anmeldung in portal_membership.
  • Wenn Sie nach allen vorherigen Tipps die Aktion weiterhin nicht finden können, gehen Sie zu portal_actions, um die Liste von Werkzeugen zu sehen, und sehen Sie dort bei allen Anbietern von Aktionen nach.

Plone sucht auf folgende Art und Weise nach Aktionen:

  • Bei einem Objekt werden alle Aktionen abgefragt.
  • Bei jeder Aktion werden die Eigenschaften conditions, permissions und visible geprüft. Wenn sie durchgehen, wird die Aktion zurückgegeben.
  • Jede Aktion wird in der Benutzerschnittstelle angezeigt, normalerweise in Form von Reitern am Anfang des Inhalts oder oben auf der Seite.
  • Die URL dieser Aktion ist die URL des Objekts, bei der die eigentliche Aktion am Ende angefügt wird.

Bei einem Dokument unter http://localhost.com/Plone/Document123 wäre z.B. die URL zum Bearbeiten http://localhost.com/Plone/Document123/document_edit_form. Hierbei sollte Ihnen ein wichtiges Sicherheitsproblem auffallen: Die Werte der Eigenschaften conditions, permissions und visible beziehen sich auf die Anzeige der Aktion in der Liste der Aktionen. Mit anderen Worten: Wenn ein Benutzer wirklich will, kann er die URL ändern und http://localhost.com/Plone/Document123/document_edit_form eingeben, selbst dann, wenn die Rechte an der Aktion das gar nicht erlauben. Aus diesem Grund sollten Sie immer mit Rechten an den Aktionen arbeiten, die ausgeführt werden. Als Benutzer, der ein Objekt anzeigen, aber nicht bearbeiten kann, können Sie trotzdem die URL ändern, um zum Bearbeiten-Formular zu gelangen. Bis hierher ist noch kein echter Schaden entstanden, da nach dem Abschicken des Formulars die Sicherheit neu überprüft und Ihnen dann die Erlaubnis verweigert wird.

Normalerweise werden Aktionen in Plone als Reiter angezeigt. Da sie aber durch ein Programm aufgerufen werden können, können sie auf beliebige Weise genutzt werden. Um eine Aktion durch ein Programm zu benutzen, rufen Sie die Methode listFilteredActionsFor im Werkzeug portal_actions auf. Bei einem gegebenen Objekt erhalten Sie damit für alle Aktionen eines Objekts ein Python-Dictionary mit Kategorien als Schlüssel:

actions = context.portal_actions.listFilteredActionsFor(object)

Damit erhalten Sie Folgendes:

{'site_actions': [
  {'category': 'site_actions', 'name': 'Small Text',
  'url': "javascript:setActiveStyleSheet('Small Text', 1);",
  'visible': 1, 'id': 'small_text',
  'permissions': ('View',)
   },
... und so weiter

Die grünen Reiter am oberen Rand sind eine Kombination zweier Kategorien: object und object_tabs. Die von der Methode zurückgegebenen Aktionen sind ein Python-Dictionary, dessen Schlüssel die Gruppe der Kategorie für diese Aktion sind. Um also nur an das Aktionsobjekt für eine Kategorie zu kommen, z.B. alle Aktionen in der Kategorie object, können Sie auf nur diesen Schlüssel des Dictionarys zugreifen. So erhalten Sie z.B. mit actions["object"] eine Liste aller dieser Aktionen:

{'category': 'object',
'name': 'Contents',
'url': ' http://localhost:8080/Plone/folder_contents',
'visible': 1,
'id': 'folderContents',
'permissions': ('List folder contents',)},
... und so weiter

Sie werden bemerken, dass, solange Sie das zu untersuchende Objekt angeben, das Werkzeug portal_types verwendet wird, um alle Aktionen für Ihren bestimmten portal_type ebenso wie andere relevante Aktionen zu finden.

Wenn Sie einen neuen Reiter zu einem Inhaltstyp hinzufügen möchten, müssen Sie lediglich zu portal_types gehen, dort den Inhaltstyp anklicken und den Actions-Reiter wählen. Dann fügen Sie Ihre Aktion hinzu. Wenn die Aktion für den Inhaltstyp als grüner Reiter erscheinen soll, dann müssen Sie sicherstellen, dass die Kategorie object_tabs lautet.

Andere Objekte im Werkzeug portal_types

Wenn Sie sich das Werkzeug portal_types anschauen, werden Sie wahrscheinlich bemerken, dass Sie zu dem Ordner andere Objekttypen hinzufügen können, z.B. DTML Method, External Method, Script (Python) und Scriptable Type Information. Die ersten drei dieser Optionen sollen Unterstützung für die letzte Option in der Liste, Scriptable Type Information, bieten.

Mit Scriptable Type Information können Sie einen Typ mit eigenen Erzeugungsrechten und einem eigenen Erzeugungsskript über das Web definieren, anstatt dass diese für Sie definiert werden. Das kommt eventuell dann in Frage, wenn die vorgegebenen Rechte bei einem Inhaltstyp nicht ausreichen. Diese Option scheint zwar sehr nützlich, aber dennoch habe ich noch nie einen guten Anwendungsfall für Scriptable Type Information gegenüber der normalen Factory-basierten Typinformation gesehen, denken Sie also nicht zu viel darüber nach.

Speichern von Inhaltstypinformationen im Dateisystem

Nun haben Sie gesehen, wie diese Information in Zope gespeichert wird, aber natürlich kommt sie irgendwoher aus dem Dateisystem. Diese Information wird normalerweise im Produkt in einem Dictionary gespeichert, das üblicherweise factory_type_information heißt. Listing 11.1 zeigt diese Factory-Information zu dem Produkt Folder, einem Produkt, das Ordner in Plone anzeigt. Sie stammt aus der Datei PloneFolder.py im Verzeichnis CMFPlone.

Listing 11.1. Factory-basierte Typinformation

factory_type_information = {
    'id':'Folder',    'meta_type':'Plone Folder',
    'description':"""\
Plone folders can define custom 'view' actions,\
 or will behave like directory listings without one defined.""",
    'icon':'folder_icon.gif',
    'product':'CMFPlone',    'factory':'addPloneFolder',
    'filter_content_types':0,
    'immediate_view':'folder_listing',    'actions':
      ( {
           'id':'view',           'name':'View',
           'action':'string:${folder_url}/',           'permissions':
(CMFCorePermissions.View,),           'category':'folder',         }
    ...
      )
    }

Das Python-Dictionary bildet die Formulare ab, die Sie in der Plone-Schnittstelle gesehen haben. So ist z.B. 'meta_type': 'Plone Folder' der meta_type des Produkts und erscheint in diesem Feld. Die Aktionen erscheinen als Liste von Dictionaries zu jeder Aktion, und es sind wiederum einfache Schlüssel/Wert-Paare für alle Eigenschaften einer Aktion. Hier habe ich nur die erste Aktion, View, angegeben, aber mittlerweile sollte Ihnen diese Art von Angaben vertraut vorkommen.

Einen neuen Inhaltstyp aus einem vorhandenen Typ erstellen

Unter Umwidmen versteht man die Erstellung mehrerer, leicht verschiedener Kopien des gleichen Typs, ausgehend von der Information eines vorhandenen Inhaltstyps. Eine Umwidmung kann dann eine schnelle und einfache Lösung sein, wenn Sie z.B. einen Typ erstellen möchten, der fast, aber nicht ganz, mit einem Nachrichtenelement identisch ist.

Der große Nachteil dieses Ansatzes ist der, dass Sie außer den Aktionen, Skins und einigen Inhaltstyp-Einstellungen nicht wirklich viel ändern können. Bevor Sie also auf diesem Weg weitermachen, machen Sie sich bitte klar, dass Sie auf diese Punkte beschränkt sind, d.h., Sie können z.B. keine neuen Felder oder Attribute hinzufügen. Auf der Mailing-Liste habe ich viele E-Mails gesehen, in denen ungefähr Folgendes steht: "Ich habe schon so viel gemacht, aber nun will ich die Attribute meiner Pressemitteilung ändern." Nehmen Sie das als Warnung: Das geht nicht! Wenn Sie mehr machen möchten, sehen Sie sich die nächsten beiden Kapitel an, in denen steht, wie Sie eigene Inhaltstypen schreiben können.

Angenommen, Sie möchten einen Typ Pressemitteilung haben, der einer Nachricht ähnelt, aber auch noch Folgendes macht:

  • Er hat den Namen Pressemitteilung in der Dropdown-Liste.
  • Er hat ein anderes Icon.
  • Er hat einen anderen Workflow als Nachrichtenelemente.
  • Er wird anders angezeigt.
  • Er hat die gleichen Datenstrukturen wie ein Nachrichtenelement.
  • Er behält den Typ eines Nachrichtenelements.

Nun, in diesem Fall ist die Umwidmung eines Inhaltstyps ideal. Nehmen Sie in diesem Beispiel die Factory-basierte Typinformation eines Nachrichtenelements, laden Sie sie in das Werkzeug portal_types, und nennen Sie sie dann Pressemitteilung. Dadurch können Sie den gesamten vorhandenen Code und die Information wiederbenutzen, während Sie auch neue Möglichkeiten haben. Gehen Sie im ZMI zu portal_types, und führen Sie folgende Schritte aus:

  1. Wählen Sie Factory-based Type Information.
  2. Geben Sie als ID Pressemitteilung ein, und wählen Sie CMF Default: News Item im Feld Use default type information.
  3. Klicken Sie auf Add, um dieses Formular zu beenden.

Das ist nun eine Instanz der Konfiguration eines Nachrichtenelements, heißt aber Pressemitteilung. Welchen Vorteil haben Sie davon? Nun, Sie haben jetzt einen weiteren Objekttyp, den Benutzer über das Web hinzufügen können. Damit haben die Benutzer Ihrer Site eine wirklich einfache Möglichkeit, zwischen einer Nachricht und einer Pressemitteilung zu unterscheiden, ohne sich mit Stichwörtern oder Metadaten herumschlagen zu müssen. Diese Objekte erscheinen nun auch bei Suchvorgängen und an allen anderen Stellen als Pressemitteilungen. Nun können Sie die Konfiguration der Pressemitteilung ändern, ohne dass es einen Einfluss auf die Konfiguration von Nachrichten hätte.

Änderungen am Icon wurden in diesem Kapitel bereits angesprochen: Laden Sie das Bild einfach in Ihr Verzeichnis, und ändern Sie dann für eine Pressemitteilung die Icon-Eigenschaft auf der Seite portal_types. Wenn Sie zum portal_workflow gehen, sehen Sie, dass alle Inhaltstypen einen eigenen Workflow haben. Da Sie nun einen neuen Inhaltstyp haben, können Sie gezielt den Workflow von Pressemitteilungen ändern. Vielleicht benötigen Pressemitteilungen eine zusätzliche Überprüfung, oder sie senden nach ihrer Veröffentlichung E-Mails an bestimmte Benutzer. Nun können Sie einen neuen Workflow erstellen, wie ich es in Kapitel 8 gezeigt habe, und ihn an Ihre Pressemitteilungen zuweisen.

Eine neue Anzeige hinzuzufügen bedeutet, das Page Template newsitem_view anzupassen und in etwas Sinnvolles umzubenennen, z.B. in pressrelease_view. Vielleicht möchten Sie diese Datei ändern, um am Seitenende einige Angaben über die Firma zu machen. Beispiel:

<h2>About ACME Widget Company</h2>
<p>Our company is the prime maker of widgets in the world. Founded
in 1980 we've been providing excellent widgets to all parts of the
globe. For more marketing information, please contact: Joe Bloggs,
marketing director.</p>

Nachdem Sie Ihre Änderungen an Ihrem neuen Page Template gespeichert haben, gehen Sie zu den Einstellungen der Pressemitteilung in portal_types zurück und gehen dort auf die Actions-Seite. Ändern Sie die Aktion für die Anzeige einer Pressemitteilung von newsitem_view in pressrelease_view. Immer, wenn Sie nun eine Pressemitteilung anzeigen, wird diese Anzeigeseite angezeigt, wie auch in Abbildung 11.1 zu sehen ist.

img/11-01.png

Abbildung 11.1. Ein in Plone geladenes Beispiel-Python-Skript

In diesem Fall habe ich ein Pressemitteilungsobjekt hinzugefügt, und die Fußzeile über ACME Company befindet sich im Template, d.h., die Benutzer müssen sie nicht immer eingeben.

Ein Skripting-Objekt erstellen

Sobald ein Objekt im Werkzeug portal_types registriert ist, können Sie dann Objektinstanzen davon in Ihrer Plone-Site erzeugen. Die Erzeugung solcher Objekte können Sie auch programmgesteuert mit Skripten durchführen. Das ist beim Erstellen von Objekten nützlich, die auf bestimmten anderen Faktoren basieren oder wenn Objekte en masse erzeugt werden. Plone hat zu diesem Zweck zwei nützliche Script (Python)-Objekte:

  • generateUniqueId: Dies erzeugt eine neue eindeutige ID für diesen Objekttyp, z.B. Folder.2003-12-19.7359814582. Sie ist nur in dem Ordner eindeutig, in dem sie erzeugt wird. Wenn Sie schnell viele Objekte erzeugen, kann es sein, dass diese nicht eindeutig sind. Aber im Normalfall ist das gut genug.
  • invokeFactory: Dies erwartet eine ID und einen Typnamen. Es erzeugt ein Objekt des angegebenen Typs und weist ihm die angegebene ID zu.

Nun werden Sie ein Beispielskript erstellen, das einen Ordner und eine Standardseite darin erzeugt, und in dieser Standardseite setzen Sie einen bestimmten Inhalt. Wenn Ihnen das bekannt vorkommt, dann vielleicht deswegen, weil das immer dann passiert, wenn Sie Mitglied auf einer Site werden und für Sie ein Home-Verzeichnis angelegt wird. Die Typnamen entsprechen der Registrierung im Werkzeug portal_types. Das heißt, wenn Sie einen Ordner erzeugen und ein Dokument darin platzieren möchten, dann müssen Sie die Parameter Folder und Document an das Skript invokeFactory übergeben.

Listing 11.2 zeigt ein Skript, das sich eine eindeutige ID holt und einen Ordner auf Basis dieser ID erstellt. Dann erstellt es in diesem Ordner ein neues Dokument.

Listing 11.2. Holen einer ID und Erstellen eines Ordners

##title=Create
##parameters=
# create with a random id
newId = context.generateUniqueId('Folder')
 
# create a object of type Folder
context.invokeFactory(id=newId, type_name='Folder')
newFolder = getattr(context, newId)
 
# create a new Document type
newFolder.invokeFactory(id='index.html', type_name='Document')
 
# get the new page
newPage = getattr(newFolder, 'index.html')
newPage.edit('html', '<p>This is the default page.</p>')
 
# return something back to the calling script
return "Done"

Wenn Sie das als Script (Python)-Objekt hinzufügen und es im Test-Reiter testen, wird ein Ordner für Sie erzeugt. Interessanterweise werden der Ordner und das Dokument im aktuellen Kontext erzeugt, was auch immer das Kontextobjekt sein mag.

Das Inhaltstyp-Register

Ich habe Ihnen eine Vielzahl verschiedener Zugriffsarten auf Plone gezeigt, z.B. FTP und WebDAV. Wenn Plone Inhalte über einen dieser Zugangswege empfängt, muss es mit diesen Inhalten in der passenden Weise umgehen. Dafür sorgt das Inhaltstyp-Register, das Sie im ZMI unter dem Werkzeug content_type_registry sehen können. Wenn Sie dieses Werkzeug in Zope aufsuchen, werden Sie wahrscheinlich von einem weiteren schlecht entworfenen Formular im ZMI geblendet, aber lassen Sie sich davon nicht entmutigen!

Wenn ein Inhalt über FTP oder WebDAV in Plone hinzugefügt wird, werden die Regeln im Register von oben nach unten ausgeführt, bis eine Übereinstimmung erfolgt. Diese basiert auf den Kriterien dieser Regel, und bei einer Übereinstimmung wird der entsprechende Inhaltstyp für diese Regel erzeugt. Folgendes sind die vier verschiedenen Arten von Kriterien:

  • major_minor: Nimmt die zwei Teile (links und rechts vom Schrägstrich) des MIME-Typs (Multipurpose Internet Mail Extensions) einer empfangenen Datei und führt darauf den Vergleich aus. Wenn Sie einen Teil leer lassen, passt dieser auf alles. Ein major_minor mit dem Wert image `` (beachten Sie das eine Leerzeichen rechts) passt z.B. auf ``image/jpeg, image/gif, image/png usw.
  • extension: Passt zur Dateinamenserweiterung. Alle Erweiterungen werden mit einem Leerzeichen voneinander getrennt. Das heißt, doc pdf passt auf rechnungen.doc und bericht.pdf.
  • mimetype_regex: Führt einen Vergleich mit einem regulären Ausdruck auf dem MIME-Typ durch. Das heißt, *,^j passt auf image/jpeg, image/jpg, application/java usw.
  • name_regex: Führt einen Vergleich mit einem regulären Ausdruck auf dem Dateinamen aus. Zum Beispiel passt ^Rechnung auf Rechnung-123.pdf, aber nicht auf Keine_Rechnung-123.pdf.

Um einen Typ hinzuzufügen, geben Sie den Namen der Regel und den Typ aus dem Dropdown-Menü im Formular am Seitenende ein und klicken auf Add. Dadurch wird am Seitenende eine Regel erstellt. In dieser Regel können Sie ein Muster eingeben, das mit der von Ihnen erstellten Art von Regel übereinstimmt, und den gewünschten Inhaltstyp in der Dropdown-Liste wählen. Dann können Sie Up und Down anklicken, um Ihren Eintrag jeweils nach oben und unten zu verschieben, um dessen Priorität zu verändern.

Ein Beispiel: Neulich habe ich eine digitale Kamera gekauft, und da das Installationsprogramm von Plone unter Windows auch CMFPhoto und PIL einrichtet, dachte ich, ich könnte aus meinen Bildern mit geringem Aufwand ein Online-Fotoalbum erstellen. Zuerst habe ich den FTP-Server aktiviert und bin dann zur Inhaltstyp-Registry gegangen, wo ich eine neue Regel erstellt habe, die von der Erweiterung abhängt, die image/jpeg auf den Inhaltstyp photo abbildet. Dann habe ich diese Regel nach oben über die vorhandene Regel für Bilder verschoben. Anschließend musste ich nur noch meine Fotos in meinen FTP-Client ziehen, und schon wurden sie automatisch in Plone geladen, mit Miniaturbildchen versehen und angezeigt.

Inhalte suchen und kategorisieren

Wie Sie in Plone nach Inhalten suchen können, haben Sie bereits gesehen, aber nun werde ich ins Detail gehen und zeigen, wie die dahinter liegende Kategorisierung und Suche von Inhalten erfolgt. Das wesentliche Werkzeug, in dem all diese Informationen gespeichert sind, heißt portal_catalog, eine leicht andere und erweiterte Version des zugrunde liegenden Werkzeugs ZCatalog. Eine sehr gute Online-Referenz zum ZCatalog finden Sie unter http://zope.org/Documentation/Books/ZopeBook/2_6Edition/SearchingZCatalog.stx.

Der Katalog bietet für eine Plone-Site drei Schlüsselelemente: Er erstellt Indizes von Inhalten, enthält Metadaten über diese Inhalte im Index und bietet eine Suchschnittstelle zum schnellen Untersuchen von Inhalten in Ihrer Plone-Site. Von all den verschiedenen Objekten in Ihrer Zope-Site werden nur die eigentlichen Instanzen Ihrer Inhaltstypen katalogisiert. Zope-Objekte, -Werkzeuge und andere Objekte kommen nicht in den Katalog. Aus diesem Grund ist das Katalog-Werkzeug eng an die Inhaltstypen und ihre Benutzung gebunden. Auf den Katalog können Sie mit dem Werkzeug portal_catalog im ZMI zugreifen.

Inhalte indizieren

Als Erstes muss der Katalog Indizes vom Inhalt erstellen. Ein Index bietet vor allem eine Methode, um schnell und effizient im Inhalt zu suchen. Daher muss der Index-Inhalt für den Benutzer nicht klar sein oder Sinn machen. Er muss nur die schnelle und effiziente Suche ermöglichen. Wenn Sie in einer Plone-Site suchen, dann suchen Sie in den Indizes, und der Katalog gibt die zur Anfrage passende Ergebnisliste zurück.

Ein Index fragt ein Plone-Objekt nach einem bestimmten Wert ab, z.B. nach einer Methode oder einem Attribut, und indiziert dann, was immer dieses Objekt bei dieser Anfrage zurückgibt. Wie es den Inhalt tatsächlich indiziert, hängt von der Art des Indexes ab. Tabelle 11.1 führt alle in Plone verfügbaren Indizes auf.

Tabelle 11.1. Verfügbare Index-Typen

Name Beschreibung
DateIndex Das dient zur Indizierung von Datumsangaben. Damit können Sie in Datums- und Zeitangaben suchen.
DateIndexRange Eine effizientere Implementation von DateIndex für Fälle mit zwei Datumsangaben, z.B. Anfangs- und Enddatum, bei denen Sie viel darin suchen müssen.
FieldIndex Behandelt jedes Ergebnis automatisch und ermöglicht es Ihnen, nach allem zu suchen, was der Index enthalten mag. Er passt bei allen Suchen im Index.
KeywordIndex Nimmt eine Folge von Stichwörtern und teilt sie in separate Wörter auf. Gibt ein Ergebnis zurück, falls eines der Stichwörter im Index auf die Anfrage passt. Ideal für die Suche nach Themen oder Stichwörtern von Objekten.
PathIndex Indiziert den Pfad eines Objekts, z.B. /Members/jane/myDocument, als Liste von Objekten. Ermöglicht die Suche im Katalog nach allen Inhalten von Members, ohne den Ordner abfragen zu müssen. Ein Pfadindex gibt alles unter dem Members-Ordner zurück.
TextIndex Ein alter Textindex, der Text nimmt, ihn aufteilt und dann indiziert. Siehe ZCTextIndex.
TopicIndex Erstellt während der Katalogisierung vordefinierte Ergebnismengen. Nützlich bei oft wiederholten Abfragen.
ZCTextIndex Ein neuer Index, der effiziente Volltext-Suchmöglichkeiten auf Textteilen bietet. Verfügt über viele verschiedene Eigenschaften, die später im Detail erörtert werden.

Welche Indizes in einem Katalog definiert sind, können Sie sehen, wenn Sie auf portal_catalog klicken und den Indexes-Reiter wählen. Dann erhalten Sie eine Liste aller in Ihrer Plone-Site definierten Indizes. Die Spalten enthalten den Indexnamen, den Typ, die Anzahl der Treffer und den Zeitpunkt der letzten Änderung im Index. Die verschiedenen Indextypen wurden zuvor kurz behandelt, aber in Tabelle 11.2 finden Sie eine Beschreibung aller Standardindizes einer Plone-Site.

Tabelle 11.2. In Plone eingerichtete Standardindizes

Name Typ Beschreibung
Creator FieldIndex Der Benutzername der Person, die das Objekt erzeugt hat.
Date FieldIndex Die Sperrfrist; falls nicht vorhanden, ist es das Datum der letzten Änderung.
Description TextIndex Das Beschreibungsfeld.
SearchableText ZCTextIndex Beschreibung, Titel und Rumpf des Objekts als ein suchbarer Text.
Subject KeywordIndex Die Stichwörter zu einem Element.
Title TextIndex Der Titel des Elements.
Type FieldIndex Der Portal-Typ, wie er im Werkzeug portal_types definiert ist.
allowedRolesAndUsers KeywordIndex Gibt an, wer diesen Inhalt anzeigen kann; eine effiziente Art, das zu untersuchen, damit Sie die Suchergebnisse filtern können.
created FieldIndex Gibt an, wann das Element erzeugt wurde.
effective FieldIndex Gibt an, wann das Element freigegeben wird.
end FieldIndex Nur bei Ereignissen; gibt an, wann das Element beendet wird.
expires FieldIndex Gibt an, wann das Element abläuft und nicht mehr sichtbar ist.
getId FieldIndex Die ID eines Elements.
id FieldIndex Identisch mit getId.
in_reply_to FieldIndex Bei Diskussionen, ergibt das Element, dem dieser Kommentar gilt.
meta_type FieldIndex Der dem Element zugrunde liegende Metatyp.
modified FieldIndex Gibt an, wann das Element zuletzt verändert wurde.
path PathIndex Der Pfad zum Element.
portal_type FieldIndex Identisch mit Type.
review_state FieldIndex Der Zustand des Objekts im Workflow.
start FieldIndex Nur bei Ereignissen; gibt an, wann das Ereignis beginnt.

Wenn Sie einmal nicht genau wissen sollten, was in einem Index enthalten ist, können Sie sich im ZMI dessen Inhalt anschauen. Klicken Sie auf portal_catalog, und wählen Sie Catalog, womit Sie eine Liste aller gerade katalogisierten Objekte erhalten. Klicken Sie auf ein Objekt, und es erscheint ein Fenster mit dem Inhalt des Indexes und der Metadaten. Die Metadaten kommen zuerst, d.h., Sie müssen nach unten scrollen, um die Indizes zu sehen.

Um Indizes zu ändern, zu löschen oder hinzuzufügen, gehen Sie zum Indexes-Reiter zurück. Benutzen Sie das normale Dropdown-Menü namens Add, um einen neuen Index hinzuzufügen oder einen zu löschen. Wenn Sie einen bestimmten Index neu erstellen möchten, wählen Sie links die gewünschten Indizes und klicken auf den Button Reindex. Wenn Sie einen Index zum Katalog hinzufügen, hat er zunächst keinen Inhalt, d.h., Sie müssen dann auf den Button Reindex klicken, um sicherzugehen, dass Ihr Index auch einen Inhalt hat.

Hinweis

Wenn Ihre Site sehr groß ist, kann diese Indizierung ziemlich viel Zeit und Prozessorleistung in Anspruch nehmen. Das heißt, Sie werden diesen Vorgang vermutlich nicht dann ausführen wollen, wenn das System gerade unter Spitzenlast fährt.

Metadaten

Die vom Katalog zurückgegebenen Ergebnisse sind nicht die gefundenen Objekte, sondern die dazu im Katalog gefundenen Metadaten. Diese Metadaten bestehen aus einer Reihe von Feldern oder Spalten für alle Werte im Objekt. Entsprechend wird für eine Plone-Site eine Liste von Spalten erzeugt, wie es in Tabelle 11.3 beschrieben ist.

Tabelle 11.3. In Plone verfügbare Standard-Metadaten

Name Beschreibung
CreationDate Das Datum der Erzeugung des Objekts.
Creator Der Benutzername der Person, die das Objekt erzeugt hat.
Date Die Sperrfrist; falls nicht vorhanden, dann das Datum der letzten Änderung.
Description Das Beschreibungsfeld.
EffectiveDate Die Sperrfrist.
ExpiresDate Das Ablaufdatum.
ModificationDate Das Änderungsdatum.
Subject Die Stichwörter des Objekts.
Title Der Objekttitel.
Type Der portal_type des Objekts.
created Identisch mit CreationDate.
effective Identisch mit EffectiveDate.
end Nur bei Ereignissen, das Ende des Ereignisses.
expires Gibt an, wann das Objekt abläuft.
getIcon Das Icon des Objekts.
getId Die ID des Objekts.
getRemoteUrl Nur bei Links; die URL, auf die der Link zeigt.
id Identisch mit getId.
location Nur bei Ereignissen; gibt an, wo das Ereignis eintritt.
meta_type Der meta_type des Objekts.
modified Gibt an, wann das Objekt verändert wurde.
portal_type Der portal_type des Objekts.
review_state Der Zustand des Objekts im Workflow.
start Nur bei Ereignissen; gibt an, wann das Ereignis eintritt.

Wie Objekte indiziert werden

Inhaltstypen werden automatisch indiziert, weil sie von einer Klasse namens PortalContent erben, die ihrerseits von einer Klasse namens CMFCatalogAware erbt. Die Klasse CMFCatalogAware enthält den gesamten Code, der sicherstellt, dass beim Hinzufügen, Bearbeiten, Ausschneiden, Kopieren, Löschen oder Umbenennen eines Objekts der Katalog (und ebenso der Workflow) aktuell sind. Das Objekt wird im Wesentlichen an den Katalog übergeben, wo die passende Anweisung aufgerufen wird (indizieren, aus dem Index entfernen usw.).

Der Katalog geht dann alle Indizes durch und fragt alle aus dem Objekt mit Hilfe der Attribute oder Methoden des Objekts ab. Bei den meisten Indizes ist der Name des gesuchten Attributs bzw. der gesuchten Methode identisch mit dem des Indexes. Beim Indexnamen Title würde er nach einem Attribut oder einer Methode namens Title suchen und im Index das Ergebnis ablegen. Dann setzt er diesen Vorgang mit allen anderen Metadatenspalten fort.

Zwei Ausnahmen bei diesem Vorgang sind die Typen FieldIndex und TopicIndex. Wenn Sie einen FieldIndex hinzufügen, können Sie angeben, dass der Index einen anderen Wert als den Namen des Indexes untersucht. Sie könnten z.B. einen Index mit der ID getVersion anlegen, der Versionswerte untersucht. Wie Sie später noch sehen werden, haben manche Indizes Vorteile gegenüber anderen, d.h., es kann sinnvoll sein, verschiedene Indizes für den gleichen Wert zu haben.

TopicIndex ist insofern ein anderer Indextyp, als er bei der Erstellung des Inhaltsindexes eine Reihe von Mengen bildet. Wenn Sie viele Suchvorgänge auf allen Bildern durchführen möchten, könnten Sie eine Suche nach o.portal_type == 'Image' hinzufügen. Dazu müssen Sie einen TopicIndex erstellen und dann im Indexes-Reiter auf den Index klicken. Sie können einen Index sogar mit mehreren Ausdrücken erstellen. In Plone wird momentan nirgendwo ein TopicIndex verwendet.

Wie indizieren Sie alle Inhalte Ihrer Plone-Site neu?

Wenn Sie eine große Anzahl von Änderungen auf Codeebene vorgenommen, ein neues Produkt installiert, Ihr Plone-Wurzelobjekt umbenannt oder verschoben haben, müssen Sie eventuell den gesamten Inhalt auf Ihrer Site neu indizieren. Klicken Sie im ZMI hintereinander auf portal_catalog, Advanced und Update Catalog. Dann wird Ihr Katalog aktualisiert.

Achtung

Diese Aufgabe ist noch aufwendiger als die Neuindizierung nur eines Indexes, und sie kann lange Zeit in Anspruch nehmen und viel Speicher und Rechenzeit benötigen, wenn Ihre Datenbank entsprechend groß ist.

Suchen im Katalog

Die wichtigste Frage ist natürlich die, wie man im Katalog sucht und dessen Ergebnisse nutzt. Der erste Teil dieser Aufgabe hängt von den Indizes ab, daher behandle ich alle Indizes und zeige Ihnen, wie man darin sucht. Der zweite Teil beinhaltet die Manipulation der Ergebnisse, die ich Ihnen anschließend auch zeigen werde.

Alle folgenden Beispiele sind in Python geschrieben, weil dies die beste Art ist, in einem Katalog zu suchen. Ich zeige Ihnen auch schnell ein Beispiel dafür, wie man das in ein Page Template einbaut. Ich möchte Ihnen nahe legen, Python für die Manipulation des Katalogs einzusetzen, weil es wirklich der beste Platz mit der höchsten Flexibilität ist, um etwas zu machen, ohne sich um die Syntax sorgen zu müssen.

Ganz allgemein bewerkstelligen Sie eine Suche dadurch, dass Sie die Methode searchResults auf dem Objekt portal_catalog aufrufen und dabei eine Reihe von Schlüsselwortparametern übergeben. Zwar gibt es ein paar reservierte Schlüsselwörter, aber der Rest wird direkt auf die Indizes gleichen Namens abgebildet. Wenn Sie also z.B. im Index SearchableText suchen möchten, würden Sie der Suchmethode den Schlüsselwortparameter für SearchableText übergeben. Folgendes sind die reservierten Schlüsselwörter:

  • sort_on: Dies ist der Index, mit dem die Ergebnisse sortiert werden sollen, vorausgesetzt, dass der Index eine Sortierung erlaubt (Volltext-Indizes tun das nicht).
  • sort_order: Hat einen der Werte reverse oder descending. Wenn nichts angegeben ist, lautet die Voreinstellung ascending.
  • sort_limit: Dies ist ein Optimierungshinweis, um die Sortierung etwas zu beschleunigen.

Eine allgemeine Suche nach allen Elementen, in denen Plone erwähnt wird, und die in der Reihenfolge von Date veröffentlicht sind, sieht ungefähr wie folgt aus:

context.portal_catalog.searchResults(
    review_state = "published",
    SearchableText = "Plone",
    sort_order = "Date"
)

Die Suche gibt die Schnittmenge der Indexergebnisse zurück, d.h., es werden alle Elemente gefunden, die Plone erwähnen und die veröffentlicht sind. Sie können keine Suche mit der Vereinigungsmenge von Ergebnissen durchführen, aber Sie könnten mehrere Ergebnisse bekommen und diese zusammensetzen, was allerdings ein eher unüblicher Fall ist.

Tipp

Wenn Sie eine Suche ohne Werte durchführen, wird der gesamte Inhalt des Katalogs zurückgegeben. Standardmäßig werden bei allen Suchvorgängen Werte für Sperrfrist und Ablaufdatum angegeben, um sicherzustellen, dass Sie nur Inhalte zwischen diesen Zeitpunkten sehen, es sei denn, der Benutzer, der die Suche ausführt, verfügt über das Recht Access inactive portal content.

Suche in einem Feld- oder Datumsindex

Bei der Suche in einem FieldIndex übergeben Sie den Wert des Feldes. Alle passenden Treffer werden zurückgegeben. Hiermit z.B. können Sie alle Bilder in einer Site suchen:

results = context.portal_catalog.searchResults(
    Type = "Image"
)

Ein Feldindex kann auch einen Bereich von Objekten annehmen, wobei dann der Index versucht, alle Werte dazwischen zu finden, indem er einen Vergleich der Werte vornimmt. Dieser Bereich könnte zwischen zwei Datumsangaben, zwei Zahlen oder zwei Strings liegen, es hängt wirklich nur vom Wert von FieldIndex ab. Dabei übergeben Sie ein Dictionary an den Index statt nur eines Strings. Das Dictionary sollte zwei Werte enthalten: eine Liste namens query mit den zu testenden Werten und einen Wertebereich. Dieser Bereich ist einer der folgenden Strings:

  • min: Alles, was größer ist als das kleinste Element
  • max: Alles, was kleiner ist als das größte Element
  • minmax: Alles zwischen dem kleinsten und dem größten Element

Verwenden Sie z.B. Folgendes, um alle Ereignisse mit einer Startzeit größer als jetzt (mit anderen Worten alles, was in der Zukunft liegt) zu finden:

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

Um Elemente in einem Bereich zu suchen, z.B. alle Nachrichten im Dezember, müssen Sie die Start- und Endzeiten des Monats berechnen. Mit diesen Daten können Sie dann die folgende Abfrage erstellen:

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

Datumsindizes funktionieren auf die gleiche Weise wie Feldindizes, und oftmals werden Sie Datumsangaben innerhalb von Feldindizes sehen, was prima funktioniert.

Suche in einem KeywordIndex

Ein KeywordIndex gibt standardmäßig alle Werte zurück, die im Stichwortindex gefunden werden. Der einzige KeywordIndex ist Subject. Das ist das Stichwort, das ein Benutzer einem Objekt mit Hilfe des Eigenschaften-Reiters in der Plone-Schnittstelle zugewiesen hat. Benutzen Sie Folgendes, um nach allen Elementen mit dem Stichwort Afrika zu suchen:

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

Ähnlich wie beim FieldIndex kann auch an KeywordIndex eine kompliziertere Abfrage mit mehreren Objekten und einem and/or-Operator übergeben werden (or ist die Vorgabe). Damit können Sie alle Objekte mit einer fast beliebigen Kombination von Stichwörtern finden. Benutzen Sie z.B. Folgendes, um alle Objekte zu finden, die die Stichwörter Afrika und Sonne enthalten:

results = context.portal_catalog.searchResults(
        Subject = { "query": ["Afrika", "Sonne"],
                     "operator": "and" }
)
Suchen in einem Pfadindex

Mit einem Pfadindex können Sie in allen Objekten eines bestimmten Pfades suchen. Es werden alle Objekte unterhalb eines bestimmten Ortes angegeben. Wenn Sie also nach allen Objekten in Members fragen, erhalten Sie alles, was in den Home-Verzeichnissen aller Mitglieder enthalten ist. Eine solche Suche nach allem, was Members im Pfad hat, sieht wie folgt aus:

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

Wenn Sie das weiter einschränken möchten, können Sie das tun, indem Sie einen Ebenenparameter übergeben, der angibt, wo Sie das Element erwarten. Die Ebene ist eine Zahl, die für seine Position im Pfad steht, und zwar von links aus gesehen, wenn man ihn an den Schrägstrichen aufteilt. Im vorherigen Code z.B. liegt Plone auf der Ebene 0, Members auf der Ebene 1 usw. Ähnlich wie beim KeywordIndex können Sie auch hier einen and/or-Operator übergeben. Um z.B. alle Objekte in den Ordnern /Plone/Members/danae und /Plone/testing/danae zu erhalten, benutzen Sie Folgendes:

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

ZCTextIndex ist der komplizierteste aller Indizes und verfügt über eine große Zahl von Optionen. Jeder ZCTextIndex benötigt ein Lexikon, aber Plone erzeugt und konfiguriert glücklicherweise all das von sich aus. Wenn Sie auf portal_catalog klicken, den Contents-Reiter wählen und dann auf plone_lexicon klicken, können Sie die Standardkonfiguration des Lexikons sehen. Mit einem Klick auf den Query-Reiter sehen Sie alle Wörter, die im Lexikon enthalten sind, das aus den Inhalten Ihrer Plone-Site erstellt wurde.

Der ZCTextIndex wird mit dem Format durchsucht, das ich in Kapitel 3 beschrieben habe. Es arbeitet mit ähnlichen Suchbegriffen, wie Sie sie auch bei Google oder anderen Suchmaschinen benutzen können. In der einfachsten Form können Sie wie folgt nach einem beliebigen Begriff suchen (beachten Sie, dass hierbei die Schreibweise irrelevant ist):

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

Aber Sie können auch alles Folgende suchen:

  • Globbing: Verwenden Sie einen Stern für beliebig viele Buchstaben. So passt z.B. Dien* auf Dienstag und Dienstage. Am Wortanfang können Sie allerdings keinen Stern verwenden.
  • Einzelne Fragezeichen: Verwenden Sie ein Fragezeichen für einen Buchstaben. Beispiel: Ro?e passt auf Rose, Robe, Rote usw. Am Wortanfang können Sie jedoch kein Fragezeichen verwenden.
  • And: Mit and geben Sie an, dass die beiden Begriffe rechts und links davon vorhanden sein müssen. Beispiel: Rom and Dienstag gibt nur Ergebnisse zurück, in denen beide Wörter im Inhalt vorkommen.
  • Or: Mit or geben Sie an, dass mindestens einer der Begriffe vorkommen muss. Beispiel: Rom or Dienstag gibt Ergebnisse zurück, falls eines der Wörter im Inhalt vorkommt.
  • Not: Mit not erhalten Sie Ergebnisse, in denen der Begriff nicht vorkommt (es wird ein and als Präfix benötigt). Beispiel: Willkommen and not Seite würde passende Seiten zurückgeben, in denen Willkommen, aber nicht Seite vorkommt.
  • Phrases: Sätze können Sie in doppelten Anführungszeichen (") setzen, um damit mehrere Wörter nacheinander anzugeben. Beispiel: "Diese Seite" passt auf Diese Seite führt Sie ins Plone Content-Management-System ein., aber nicht auf Diese Startseite von....
  • Not phrase: Sie können einem Satz ein Minuszeichen (-) als Präfix voranstellen. Beispiel: Start -"Diese Seite" passt auf alle Seiten, in denen Start vorkommt, aber nicht Diese Seite.

Tipp

Wenn Sie eine Suche ohne Text durchführen, werden keine Ergebnisse zurückgegeben.

Die Ergebnisse benutzen

Nun haben Sie also einige Ergebnisse, aber was fangen Sie damit an? Die meisten Leute sehen sich als Erstes die Ergebnisse an und nehmen dabei an, dass es sich um eine Liste der katalogisierten Objekte handelt. Das ist aber nicht der Fall, sondern es handelt sich um eine Folge von "Kataloghirnen" (engl. catalog brains). Diese Hirne sind tatsächlich "Lazy"-Objekte, die die zuvor definierten Metadatenspalten enthalten. Auf all diese Spalten können Sie so zugreifen, als ob es sich um Attribute handeln würde. Verwenden Sie Folgendes, um z.B. alle IDs der Ergebnisobjekte auszugeben:

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

In diesem Beispiel ist getId der Name einer Metadatenspalte, d.h., sie wird den Wert von getId anzeigen, der im Katalog für dieses Objekt enthalten ist. Wenn Sie versuchen, auf einen Wert zuzugreifen, der nicht als Metadatenspalte existiert, erhalten Sie einen AttributeError. Folgendes sind ein paar nützliche Methoden solcher Hirne:

  • getPath: Gibt den physischen Pfad dieses Objekts in Zope zurück.
  • getURL: Gibt die URL für dieses Objekt zurück, bei der Virtual Hosting angewendet wurde.
  • getObject: Gibt das eigentliche Objekt zurück.
  • getRID: Eine eindeutige ID für das Objekt im Katalog, die sich jedes Mal ändert, wenn das Objekt nicht mehr katalogisiert ist. Ist nur für interne Aufgaben gedacht.

Wenn Sie also für jedes Ergebnis das Objekt haben möchten, können Sie das haben, wie Sie im folgenden Beispiel gleich sehen werden. Allerdings gibt es einen Grund dafür, warum der Katalog das nicht selbst macht: Diese Operation ist aufwendig in puncto Rechenzeit, weil damit ein Weckvorgang des Objekts (und aller Objekte dazwischen) verbunden ist, bei dem es aus der Datenbank geholt wird, und außerdem werden viele Sicherheitsprüfungen vorgenommen. Wenn Sie es einrichten können, dass Ihre Metadaten die passende Information enthalten, werden Sie eine wesentlich schnellere Anwendung haben. Natürlich können Metadaten manchmal nicht alles enthalten, aber eine Überlegung ist es beim Entwurf wert. Um an alle Objekte zu kommen, können Sie Folgendes benutzen:

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

Da Sie über eine Python-Liste dieser Hirne verfügen, ist es nun sehr leicht, die Ergebnisse in der geeigneten Weise zu manipulieren. Um herauszufinden, wie viele Ergebnisse gefunden wurden, können Sie einfach wie folgt die Funktion len auf der Liste aufrufen:

results = context.portal_catalog.searchResults()
print "Anzahl der Ergebnisse", len(results)
return printed

Hinweis

len ist eine Python-Funktion, die Ihnen die Länge eines Objekts mitteilt.

Um nur die ersten zehn Elemente zu bekommen, verwenden Sie einen Python-Teilbereich wie folgt:

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

Um eine weitere Filterung vorzunehmen, können Sie die gesamte Liste wie folgt manuell filtern:

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 occurence of a word
    if result.Title.find("Plone") > -1:
        print result.Title
return printed

Um ein zufällig gewähltes Objekt aus dem Katalog zu erhalten, können Sie das Modul random wie folgt benutzen:

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

Alles zusammen: Erstellen eines Suchformulars

In den vorangegangenen Betrachtungen habe ich Ihnen gezeigt, wie Sie einige Ergebnisse aus dem Katalog bekommen, und ich habe Script (Python)-Objekte benutzt, um das zu demonstrieren. Aber vermutlich fragen Sie sich, wie Sie das aus einem Page Template tun können?

Ich fange am anderen Ende an und nehme zuerst an, dass Sie die Ergebnisse aus einer Kataloganfrage schon haben und in einem Page Template mit tal:repeat darüber iterieren. Auf diese Weise funktionieren eine Menge Portlets, auch die für zuletzt veröffentlichte Elemente und Ereignisse, die beide lediglich den Katalog abfragen und dann die Ergebnisse anzeigen. Diese Portlets betten die Abfrage in einem Page Template ein, entweder, indem sie dieses direkt aufrufen:

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

oder indem sie ein separates Script (Python)-Objekt aufrufen, das die Ergebnisse zurückgibt. Im folgenden Beispiel heißt das Skript getCatalogResults:

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

In einem Page Template würden Sie die Ergebnisse auf folgende Weise erhalten:

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

Danach müssen Sie mit der normalen tal:repeat-Syntax über die Ergebnisse iterieren. Auf alle Metadatenspalten können Sie direkt in TAL (Template Attribute Language) mit einem Pfadausdruck auf die Spalte zugreifen. Mit einem gegebenen Hirn könnten Sie mit einem Aufruf von result/Title den Titel aus den Metadaten ermitteln. Listing 11.3 zeigt eine Beispielseite, die über den Inhalt von getCatalogResults iteriert und jedes Element in einer einfachen ungeordneten Liste anzeigt.

Listing 11-3. Iterieren über getCatalogResults

<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>

Ein Merkmal der Methode searchResults ist, dass sie bei einem Aufruf ohne Parameter in der ankommenden Abfrage nach diesen sucht. Wenn Sie also möchten, dass ein Formular Parameter zu Ihren Ergebnissen hinzufügt, müssen Sie nur die vorherige Ergebniszeile wie folgt ändern:

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

Nun können Sie Ihre Abfrage erneut ausführen und einen beliebigen Index zur URL hinzufügen. Wenn Sie dieses Page Template z.B. testResults nennen und in Ihrem Browser ans Ende der URL ?Type=Document hinzufügen, würden nur die Dokumente in Ihrer Site erscheinen. Da Sie fast alle Abfragewerte übergeben können, können Sie ein Suchformular so einrichten, dass diese Information zum Suchformular durchgereicht wird. Genau das machen die Seiten zur Suche und zur erweiterten Suche. Wenn Sie auf eine Plone-Site gehen und in dem Suchkasten nach Wein suchen, werden Sie bemerken, dass Ihre URL nun ?SearchableText=Wein enthält.

Listing 11.4 zeigt ein Formular zum Aufrufen Ihrer Page Templates.

Listing 11.4. Ein Formular zum Aufrufen Ihres Templates

<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 content type to search for</p>
  <form method="post" action="testResults">
    <select name="Type">
      <option
       tal:repeat="value python:here.portal_catalog.uniqueValuesFor('Type')"
       tal:content="value" />
        </select>
        <br />
        <input type="submit" class="context">
    </form>
</div>
</body>
</html>

Dieses Skript benutzt eine Methode namens uniqueValuesFor im Katalog, die alle eindeutigen Werte zurückgibt, die in einem Index existieren. Damit können Sie eine Aufgabe wie das Ausfüllen eines kleinen Dropdown-Menüs in einem Formular erledigen, was sehr nützlich ist.

An diesem Punkt wird es zu einer Übung in HTML und Page Templates, Ihre Seiten so komplex zu machen, wie Sie es wünschen. Der beste Platz, um all das nachzuschauen, ist natürlich in den echten Templates von Plone, die viele Zeilen mit tollen Beispielen enthalten. Alle Portlets, die Sie in Plone kennen (z.B. der Kalender, die Ereignisse, Dazu passend usw.) sind so aufgebaut, dass Sie Katalogabfragen benutzen, um zu bestimmen, was angezeigt werden soll.

In diesem Kapitel habe ich Ihnen einen Überblick über Methoden gezeigt, um eine Plone-Site zu entwickeln, und ich habe gezeigt, wie Inhaltstypen in Ihrer Site funktionieren. Außerdem habe ich vorgeführt, wie ein Inhaltstyp gebaut und dann über den Katalog referenziert wird. In Plone ist das eine sehr wichtige Entwicklungsstrategie.

Im nächsten Kapitel werde ich zeigen, wie man einen neuen Inhaltstyp mehr oder weniger bei null beginnend erstellt. Und Sie werden sehen, wie Sie diesen neuen Inhaltstyp mit dem Katalogregister im Werkzeug portal_types integrieren können.


Andy McKay: Plone. Addison-Wesley 2005
Diese online Version wurde mit Hilfe des 'PloneBookDE' Produkts von docs.neuroinf.de/products erstellt.
Es wurde zuletzt von
loesch am 2006-01-11 13:38 aus der fallback Quelle aktualisiert.

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: