Search the FirstSpirit Knowledge Base
Hallo,
ich versuche mich aktuell an einem Skript, welches projektweit nach einem Linktemplate suchen, den Inhalt auslesen und bei Bedarf ändern soll.
Konkret geht es um ein Linktemplate, welches die Eingabe von Links in einem CMS_INPUT_TEXT erlaubt.
Diesen Inhalt möchte ich ändern, weil wir aktuell unsere Webseite umstrukturieren. Damit würde den Redakteuren eine Menge Arbeit erspart.
Was ich bisher habe ist das holen der Referenzen des Linktemplates per:
TemplateStoreRoot templateStore = userService.getTemplateStore();
LinkTemplates linkTemplates = templateStore.getLinkTemplates();
LinkTemplate linkTemplate = linkTemplates.getTemplate("link_external");
ReferenceEntry[] references = linkTemplate.getIncomingReferences();
Allerdings bekomme ich da nicht die jeweilige Instanz der Linkvorlage, sondern die des übergeordneten Elementes.
Davon gibt es bei uns allerdings eine Menge. Aktuell habe ich 18 Templates identifiziert, die dieses Linktemplate einbinden können.
Muss ich nun alle 18 Varianten im Skript durchgehen und mich vom übergeordneten Element bis zum gesuchten link Element durcharbeiten, damit ich die Änderung vornehmen kann?
Gibt es einen leichteren Weg, um zum Beispiel direkt alle Instanzen des Linktemplates zu bekommen?
Viele Grüße
Nick
Edit:
Ich habe bereits einen älteren ähnlichen Beitrag gefunden (URLs von Links via Skript modifizieren ). Hier scheint nur der Weg über alle 18 Wege zu iterieren zu funktionieren.
Hallo Nick,
auf jeden Fall solltest du schon mal das setTemplate weglassen. Und dir fehlt das speichern, sowie das setzen der FormDatas.
Zudem gibt es noch eine Besonderheit - bei mir hat es immer Probleme gemacht, wenn ich den Link aus der LinkNode "wiederverwendet" habe. Ich musste immer einen neuen erstellen und die FormData übertragen. Das könnte dann alles in allem so aussehen:
parentPage.setLock(true, true);
FormData frmData = section.getFormData();
FormField<?> domEditor = frmData.get(language, "st_text");
DomElement domElement = (DomElement) domEditor.get();
DefaultDomNode domRoot = domElement.getRoot();
for (DomNode node : domRoot.getChildren(true)) {
if (node.getNodeType() == DomNodeType.LINK) {
LinkDomNode linkNode = (LinkDomNode) node;
Link link = linkNode.getLink();
if ("textlinkexternal".equals(link.getTemplate().getUid())) {
Link newLink = link.getTemplate().createLink(link.getLinkLanguage()); // Neuen Link erzeugen
FormData linkFormData = link.getFormData();
FormField<?> refField = linkFormData.get(null, "ref");
String oldText = (String) refField.get();
String newText = oldText.replaceAll("e", "a");
refField.set(newText); // Neuer Wert dem FormField zuweisen
newLink.setFormData(linkFormData); // Aktualisierte FormData dem Link zuweisen
linkNode.setLink(newLink); // Link der LinkNode zuweisen
}
}
}
domEditor.set(domElement); // Wert im CMS_INPUT_DOM setzen
section.setFormData(frmData); // Aktualisierte FormData der Section zuweisen
parentPage.save();
parentPage.setLock(false, true);
Gruß
Felix
Hallo Nick,
Ja, das ist korrekt - du wirst alle Wege abdecken müssen. Ich mache dies in der Regel so, dass ich eine Funktion habe, die eine FormData entgegennimmt und dann über die formularelemente iteriert. Ist das Element wieder ein Container für eine FormData (bspw. FS_List) so ruft sich die Funktion selbst auf - damit hast du die verschiedenen Ebenen schon mal abgedeckt. Für alle weiteren formularelemente musst du entsprechend nur den link ermitteln - also für cms_input_link und dom/domtable. 18 Varianten dürftest du also nicht brauchen - eher ein paar für die verschiedenen container für die FormData + die Elemente, die direkt den link enthalten können. Wenn du detailliertere infos brauchst kannst du ja hier nochmal antworten oder mir eine pn schicken.
Gruß
Felix
Hallo Felix,
ich tue mich aktuell noch schwer damit von der FormData auf das Link Element zu kommen.
Könntest du mir ein Beispiel geben wie das gemacht wird?
Viele Grüße
Nick
Hallo Nick,
von der FormData holst du dir über .getForm().forms() die GomFormElemente. Für diese machst du dann einen Switch zur Unterscheidung - bspw. auf den Tag-Name (.getGomElementTag()).
Für alle Eingabekomponenten musst du entsprechend schauen, wie du den Link bzw. die FormData ersetzt - das ist dann in der ODFS aber in der Regel gut beschrieben.
Bei weiteren Fragen einfach melden 😉
Viele Grüße
Felix
Hallo Felix,
schon einmal Danke für deine Hilfe!
Ich steh allerdings immer noch auf dem Schlauch.
Das habe ich bisher:
LinkTemplate linkTemplate = linkTemplates.getTemplate(templateName);
ReferenceEntry[] referenceEntry = linkTemplate.getIncomingReferences();
this.masterLanguage = project.getMasterLanguage();
for (ReferenceEntry reference : referenceEntry) {
IDProvider referencedElement = reference.getReferencedElement();
if (!(referencedElement instanceof Section)) {
String name = referencedElement.getName();
Section section = (Section) referencedElement;
IDProvider body = section.getParent();
if (body == null) {
System.out.println("Unexpected error: Parent of Section (=body) was null for section with name = " + name);
continue;
}
IDProvider tmpParentPage = body.getParent();
if (tmpParentPage == null || !(tmpParentPage instanceof Page)) {
System.out.println("Unexpected error: Parent page for " + name + " was " + (tmpParentPage == null ? "null" : "of type of " + tmpParentPage.getClass().toString()));
continue;
}
Page parentPage = (Page) tmpParentPage;
FormData sectionData = section.getFormData();
Iterable<GomFormElement> iter = sectionData.getForm().forms();
for (GomFormElement gom : iter) {
if(gom.getGomElementTag().equalsIgnoreCase("CMS_INPUT_DOM")){ // Hier weiß ich, dass das aktuell GomFormElement ein CMS_INPUT_DOM ist
GomDom dom = (GomDom) gom;
GomLinkEditorList it = dom.getLinkEditors();
Iterator<GomNamedEntry> it2=it.iterator() ;
while (it2.hasNext()){
GomNamedEntry elem = it2.next();
if(elem.getGomElementTag().equalsIgnoreCase("LINKEDITOR")){
// Hier weiß ich, dass es ein LINKEDITOR ist. Da kann ich noch auf den korrekten referenznamen des Templates prüfen.
// Wie komm ich von einem GomNamedEntry auf ein Link Element?
// Ist der Ansatz denn korrekt?
}
}
}
}
}
}
Scheinbar kann ich dann (Zeile 34) mit dem GomNamedEntry einfach gar nichts mehr anfangen?
Für mich sieht es zumindest so aus, dass ich mich für den Fall Input_Dom schon einmal bis ganz nach unten durchgehangelt habe an die Stelle, die ich gerne ändern würde.
Aber hier sehe ich aktuell keine Möglichkeit die Änderung durchzuführen?
Wo ist denn hier der Fehler?
Falscher Ansatz?
Viele Grüße
Nick
Hallo Nick,
das GomFormElement nutzt du nur, um den Tag herauszufinden und holst dir dann die Value wieder über die FormData.
Hier mal ein Snippet, das ich öfters verwende:
/**
* Das hier ist deine Methode um FormDatas allgemein zu migrieren:
*/
private FormData migrateFormData(FormData formData){
for (GomFormElement form : formData.getForm().forms()) {
// Hier unterscheidest du welche Art von FormField es ist
String tag = form.getGomElementTag();
switch (tag){
case "CMS_INPUT_DOM":
FormField<?> domField = formData.get(language, form.name());
DomElement domElement = (DomElement) domField.get();
domField.set(migrateDom(domElement));
break;
case "FS_LIST":
// Über Kinder ignorieren und migrateFormData für die IdProvidingFormData aufrufen
break;
case "FS_CATALOG":
// Analog zu FS_LIST
break;
case "CMS_INPUT_LINK":
// Die FormData vom Link holen und ebenfalls migrateFormData aufrufen
break;
case "FS_REFERENCE":
// Hier dann die Referenz ersetzen
break;
}
}
return formData;
}
/**
* Hier einfach über die DOM Kinder iterieren, den Link holen und das selbe Spiel wie bei CMS_INPUT_LINK machen
*/
private DomElement migrateDom(DomElement domElement){
DefaultDomNode domRoot = domElement.getRoot();
for (DomNode node : domRoot.getChildren(true)) {
if (node.getNodeType() == de.espirit.firstspirit.access.editor.value.DomNodeType.LINK) {
LinkDomNode linkNode = (LinkDomNode) node;
Link link = linkNode.getLink();
FormData linkFormData = link.getFormData();
link.setFormData(migrateFormData(linkFormData));
linkNode.setLink(link);
}
}
}
In meinem Fall rufe ich bei link.setFormData() wieder migrateFormData auf, weil ich mit dem Snippet die Referenzen auf eine Seite umbiege. Wenn du nur ein Text-Feld im Link änderst solltest du dafür dann ne eigene Methode noch hinzufügen oder es direkt im migrateDom machen.
Gruß
Felix
Hallo Felix,
ich habe noch ein wenig rumprobiert und bin auf folgendes gekommen.
Zuerst iteriere ich über die ReferenceEntry[] Liste und hole mir da die Liste Iterable<GomFormElement> per .getForm().forms()
Da prüfe ich dann auf getGomElementTag().equalsIgnoreCase("CMS_INPUT_DOM") um an die DomElemt Felder zu kommen.
Habe ich so ein Element, iteriere ich über die Children (DomNode) und prüfe dann für einen bestimmten Fall, ob das Child Element ein Link ist.
if (node.getNodeType() == de.espirit.firstspirit.access.editor.value.DomNodeType.LINK)
Mein Plan war jetzt an dieser Stelle, dass ich ja "nur noch" an die URL aus dem CMS_INPUT_TEXT Feld rankommen und ändern muss.
Das habe ich so versucht:
LinkDomNode linkNode = (LinkDomNode) node;
Link link = linkNode.getLink();
link.setTemplate(linkTemplate);
Jetzt kann ich per link.get("st_ref") die URL auslesen. Per System.out. kann ich mir exakt den Wert ausgeben lassen, den ich ändern möchte.
Was mir jetzt nur fehlt ist, den geänderten Wert auch wieder zurück zu schreiben.
Versucht habe ich es wie folgt:
parentPage.setLock(true);
FormData lfd = link.getFormData();
String oldlink = link.get("st_ref").toString();
lfd.get(masterLanguage, "st_ref").set(oldlink.replace(searchPattern, replacePattern));
link.setFormData(lfd);
System.out.println("link.get(st_ref).toString(): " +link.get("st_ref").toString());
linkNode.setLink(link);
System.out.println("link Node gesetzt");
System.out.println("link.getTemplate(): " +link.getTemplate());
link.setTemplate(linkTemplate);
System.out.println("link.getTemplate(): " +link.getTemplate());
parentPage.release();
System.out.println("parentPage released");
parentPage.setLock(false);
System.out.println("parentPage setLock");
Der Plan war hier, zunächst einmal die Eltern Seite zu locken.
Anschließend über FormData den Link auszulesen und über die FormData zu ändern und wieder an den link zu setzen.
Laut den System.out Meldungen funktioniert es auch.
Ich bekomme den alten Link vor dem replace und den neuen nach dem set FormData.
Der Rest des Codes läuft auch einfach durch, es kommt zu keiner Fehlermeldung und ich bekomme die Logausgaben per System.out auf der Java Konsole angezeigt.
Allerdings wird in der Testseite nichts geändert. Der Inhalt bleibt nach wie vor der selbe.
Wo liegt denn hier der Fehler?
Ich bin immerhin soweit, dass ich sicher bin, dass ich auf dem richtigen Element bin. Jetzt frage ich mich nur, warum der Wert nicht gespeichert wird.
Hast du eine Idee?
Viele Grüße
Nick
Hallo Nick,
auf jeden Fall solltest du schon mal das setTemplate weglassen. Und dir fehlt das speichern, sowie das setzen der FormDatas.
Zudem gibt es noch eine Besonderheit - bei mir hat es immer Probleme gemacht, wenn ich den Link aus der LinkNode "wiederverwendet" habe. Ich musste immer einen neuen erstellen und die FormData übertragen. Das könnte dann alles in allem so aussehen:
parentPage.setLock(true, true);
FormData frmData = section.getFormData();
FormField<?> domEditor = frmData.get(language, "st_text");
DomElement domElement = (DomElement) domEditor.get();
DefaultDomNode domRoot = domElement.getRoot();
for (DomNode node : domRoot.getChildren(true)) {
if (node.getNodeType() == DomNodeType.LINK) {
LinkDomNode linkNode = (LinkDomNode) node;
Link link = linkNode.getLink();
if ("textlinkexternal".equals(link.getTemplate().getUid())) {
Link newLink = link.getTemplate().createLink(link.getLinkLanguage()); // Neuen Link erzeugen
FormData linkFormData = link.getFormData();
FormField<?> refField = linkFormData.get(null, "ref");
String oldText = (String) refField.get();
String newText = oldText.replaceAll("e", "a");
refField.set(newText); // Neuer Wert dem FormField zuweisen
newLink.setFormData(linkFormData); // Aktualisierte FormData dem Link zuweisen
linkNode.setLink(newLink); // Link der LinkNode zuweisen
}
}
}
domEditor.set(domElement); // Wert im CMS_INPUT_DOM setzen
section.setFormData(frmData); // Aktualisierte FormData der Section zuweisen
parentPage.save();
parentPage.setLock(false, true);
Gruß
Felix
Hallo Felix,
vielen Dank!
Das Skript funktioniert und jetzt werden auch die Werte ausgetauscht.
Jetzt hab ich nur noch vor das umzubauen, dass man die search und replace Werte per Formular eingeben kann und dann bin ich endlich durch.
Danke für deine Hilfe! Nur mit der API hätte ich glaube ich irgendwann aufgegeben
Viele Grüße
Nick
Felix Reinhold schrieb:
Hallo Nick,
auf jeden Fall solltest du schon mal das setTemplate weglassen. Und dir fehlt das speichern, sowie das setzen der FormDatas.
Zudem gibt es noch eine Besonderheit - bei mir hat es immer Probleme gemacht, wenn ich den Link aus der LinkNode "wiederverwendet" habe. Ich musste immer einen neuen erstellen und die FormData übertragen. Das könnte dann alles in allem so aussehen:
parentPage.setLock(true, true); FormData frmData = section.getFormData(); FormField<?> domEditor = frmData.get(language, "st_text"); DomElement domElement = (DomElement) domEditor.get(); DefaultDomNode domRoot = domElement.getRoot(); for (DomNode node : domRoot.getChildren(true)) { if (node.getNodeType() == DomNodeType.LINK) { LinkDomNode linkNode = (LinkDomNode) node; Link link = linkNode.getLink(); if ("textlinkexternal".equals(link.getTemplate().getUid())) { Link newLink = link.getTemplate().createLink(link.getLinkLanguage()); // Neuen Link erzeugen FormData linkFormData = link.getFormData(); FormField<?> refField = linkFormData.get(null, "ref"); String oldText = (String) refField.get(); String newText = oldText.replaceAll("e", "a"); refField.set(newText); // Neuer Wert dem FormField zuweisen newLink.setFormData(linkFormData); // Aktualisierte FormData dem Link zuweisen linkNode.setLink(newLink); // Link der LinkNode zuweisen } } } domEditor.set(domElement); // Wert im CMS_INPUT_DOM setzen section.setFormData(frmData); // Aktualisierte FormData der Section zuweisen parentPage.save(); parentPage.setLock(false, true);
Gruß
Felix