Search the FirstSpirit Knowledge Base
Hallo liebe Community,
ich komme gerade an einem Punkt eines meiner Projektes nicht so recht weiter.
Ich möchte mit einem Modul die Werte von Verschachtelten Entities einer ContentProjektions-Detail-Seite über die API auslesen und verarbeiten.
Folgende Codeschnipsel (nicht vollständig) verwende ich im Moment:
...
List<Entity> detailPageEntities = pageRef.getContent2Params().getData(language);
...
for (Entity detailPageEntity : detailPageEntities) {
...
Object dataSourceFieldValue = detailPageEntity.getValue(dataSourceFieldName);
...
}
Das so zurückgelieferte Object kann ich dann entsprechend casten und verwenden.
Gebe ich hier allerdings den Namen einer verschachtelten Entity (im Mithras-Projekt z.B. "Categories_List" auf einer Produkt-Entity) ein, so erhalte ich eine Liste vom Typ "de.espirit.or.impl.PersistentList". Dieser Typ scheint nicht mehr Teil der öffentlichen API zu sein, zumindest habe ich ihn nicht in der JavaDoc gefunden.
Wie sieht denn der übliche Weg aus um solche Sachverhalte in einem Modul über die API abzubilden?
Ich implementiere gerade gegen das Mithras-Projekt und will dort zu z.B. jeder Detailseite eines Produkts in meinem Modul die zugehörigen Kategorien auslesen und dann verarbeiten.
Der Übergabeparameter "dataSourceFieldName" ist erst zur Laufzeit bekannt und kann vom User konfiguriert werden. Ebenso ist erst zur Laufzeit die tatsächliche Struktur des DB-Schemas bekannt. (Es kann vorausgesetzt werden, dass der User die Konfiguration korrekt auf das DB-Schema abstimmt.)
Eine Idee die ich hatte ist, den Übergabeparameter mit einer eigenen Syntax zu versehen wie z.B. "Categories_List.Name_DE". Diese könnte man dann parsen und sich von einer Produkt-Entity das Attribut "Categories_List" zurückgeben lassen und dann von allen in der zurückgegebenen Liste enthaltenen Entities das Attribut "Name_DE".
Gibt es eine elegantere/bessere Art und Weise mein Vorhaben umzusetzen?
Beste Grüße
Sandro
Hallo Sandro,
warum nutzt du dafür ein Modul? Wenn du nur, wie du beschrieben hast, "zu z.B. jeder Detailseite eines Produkts [...] die zugehörigen Kategorien auslesen und dann verarbeiten." willst, dann reicht hierfür doch eine einfache for-Schleife?
$-- eigene Variable setzen, ob es sich bei der Seite um eine Contentprojektion handelt --$
$CMS_SET(set_isContentProjection,!#global.multiPageParams.data.isEmpty)$
$CMS_IF(set_isContentProjection)$
$-- Contentprojektion liefert ein Entity pro Detailseite, dieses und das zugehörige FormData in Variablen speichern --$
$-- der Code ist vllt etwas Overkill, aber wir nutzen eine Seitenvorlage für viele verschiedene Datenquellen-Ausgaben --$
$CMS_SET(set_entity, #global.multiPageParams.data.get(0))$
$CMS_SET(set_row, #global.node.content2Params.tableTemplate.getDataset(set_entity).formData)$
$CMS_FOR(for_category, set_row.cs_categories)$
[...] tue hier irgendwas mit der jeweiligen Kategorie [...]
$CMS_END_FOR$
$CMS_END_IF$
Viele Grüße,
Nils
Hallo Nils,
das hätte ich evtl. noch dazu schreiben sollen.
Ich will die Werte nicht über einen Ausgabekanal (HTML, XML, etc.) auf der Website ausgeben sondern im Backend weiterverarbeiten. Mit den Daten soll ein Nachgelagertes System (oder z.B. einen Suchindex) befüllt werden. Diese Aufgabe wird von einem Modul übernommen, welches neben den Entities von Detailseiten auch noch viele andere Daten (Formularfelder, Metadaten, etc.) extrahiert und an das nachgelagerte System sendet.
Grüße
Sandro
Ah! Dann muss man hier natürlich etwas anders rangehen.
Ich denke, das Einfachste ist ein Executable, das per
$CMS_RENDER(script:"do_something_with_categories, formdata:set_row)$
bei der Generierung gestartet wird.
Das Executable könnte dann so ausfallen:
public class DoSomethingWithCategoriesExecutable extends Executable {
private Writer out;
private Writer err;
private final Map<String, Object> params = new HashMap<String, Object>();
@Override
public final Object execute(final Map<String, Object> params) {
return execute(params, ScriptUtil.getInfoLogWriter(getClass()), ScriptUtil.getErrorLogWriter(getClass()));
}
@Override
public final Object execute(final Map<String, Object> params, final Writer out, final Writer err) {
this.params.putAll(params);
this.out = out;
this.err = err;
return execute();
}
@Override
public Object execute() {
BaseContext context = (BaseContext) params.get("context");
Language masterLanguage = context.requireSpecialist(LanguageAgent.TYPE).getMasterLanguage();
FormData formData = (FormData) params.get("formdata");
FormField<?> categoryField = (FormField<?>) formData.get(masterLanguage, "cs_categories");
categoryField.get(); // hier bekommt man die Kategorien, mit denen man nun nach Belieben Unfug treiben kann.
return null;
}
}
Die Executable-Klasse muss hierfür noch in der module.xml angegeben sein
<public>
<name>do-something-with-categories-executable</name>
<description>lorem ipsum uswusf</description>
<class>de.pfad.zu.DoSomethingWithCategoriesExecutable</class>
</public>
Damit kommt das Skript in FirstSpirit mit folgendem Inhalt aus:
#!executable-class
do-something-with-categories-executable
Hallo Sandro,
benötigst Du noch weitere Hilfe oder haben Dir Nils' Antworten bereits geholfen?
In diesem Fall wäre es super, wenn Du die "richtige Antwort" entsprechend markierst, damit auch andere
Community-Teilnehmer diese auf den ersten Blick finden. Solltest Du zwischenzeitlich eine eigene Lösung
gefunden haben, wäre es nett, wenn Du diese hier bereitstellst.
Viele Grüße
Michaela