udo_woitek
I'm new here

Generierungsparameter aus Dateinamen ermitteln?

Jump to solution

Hallo,

in einem der Generierung nachgelagerten Modul möchte ich aus den generierten Dateinamen (zu findem im Staging-Verzeichnis) eventuell mit Hilfe des im Context gespeicherten UrlCreators die Generierungsparameter (Sprache und Vorlage) ermitteln. Für "normale" Seiten und Medien ist das noch durch ein Iterieren über die Projekt-Sprachen und -Vorlagen möglich, mit denen ich dann den UrlCreator für ein ContentProducer- oder Media-Objekt den Dateinamen nochmals erstellen lasse.

Vielleicht gibt es dafür schon einen einfacheren Weg (weiterhin unabhängig vom Typ des UrlCreator, also ohne gespeicherte URLs)?

Bei Inhaltsprojektionen scheitert dieser Weg jedoch, da ich Dateinamen mit angehängten Nummern vorliegen habe. Im Prinzip würde ich nun die Dateinamensermittlung wie oben für beliebig viele contentId-Werte vornehmen und den vorliegenden mit dem erneut generierten Dateinamen vergleichen. Das ist keine sinnvolle Option, daher meine zweite Frage: Kann ich aus einem durch Inhaltsprojektion erstellten Dateinamen auf die Generierungssprache und das Generierungstemplate schließen? Und vor allem wie?

Danke und schöne Grüße,

Udo Woitek.

1 Solution

Accepted Solutions

Hallo Udo,

vorweg: beschrieben mag sich das Ganze recht aufwändig anhören, ist aber in 30 Minuten gebaut.

1. Füge im Ausgabekanal des Projekteinstellungs-Templates folgendes hinzu:

$CMS_IF(!#global.preview && #global.scheduleContext.getProperty("gv_urlMap")==null)$  

    $CMS_SET(void,#global.scheduleContext.setProperty("gv_urlMap",{:}))$

$CMS_END_IF$

Hintergrund: Der Ausgabekanal der Projekteinstellungen wird zwar nicht "ausgegeben", aber zu Beginn jeder Generierung ausgewertet - und zwar pro Sprache und Ausgabekanal. Dieser Code legt eine leere Map in die Property "gv_urlMap" des Generierungskontextes. Diese Properties "leben" im Auftrag. Vor allem über mehrere Tasks im Auftrag. Nach Ausführung des Auftrages werden sie entsorgt.

2. Rendertemplate

Erstelle ein Rendertemplate (=Formatvorlage, z.B. "save_url_map") mit folgendem Inhalt:

$CMS_IF(!#global.preview && #global.scheduleContext.getProperty("gv_urlMap")!=null)$

    $CMS_SET(set_infoMap,{

        "nodeUid":#global.node.uid,

        "lang":#global.language.abbreviation,

        "templateSet":#global.templateSet.uid,

        "datasetTable":#global.dataset.entity.entityType.name,

        "datasetId":#global.dataset.entity.id

    })$

    $CMS_SET(set_url)$$CMS_REF(#global.ref, abs:2)$$CMS_END_SET$

    $CMS_SET(void,#global.scheduleContext

        .getProperty("gv_urlMap")

        .put(set_url.toString,set_infoMap)

    )$

$CMS_END_IF$

Die infoMap kannst Du nach Deinen Bedürfnissen anpassen, im Beispiel landen darin die UID der Seitenreferenz, die Sprache usw. Es muss nicht unbedingt eine Map sein. Du kannst auch das gv_urlMap bei Bedarf als Liste statt Map nutzen - je nachdem was am praktikabelsten ist. Da ich es aber so verstanden habe, dass Du zu den einzelnen Dateien diese Infos brauchst, macht eine Map mit den absoluten URLs als Keys hier wahrscheinlich am meisten Sinn.

Dieses Rendertemplate bindest Du in alle Seitenvorlagen ein (die Stelle ist relativ egal):

$CMS_RENDER(template:"save_url_map")$

Bis hierher hast Du also nach der Generierung eine Map mit den absoluten Pfaden als Key und einigen Infos als "Sub-Map". Diese Map "lebt" als Property im ScheduleContext.

Die Frage ist: Wie kommt man da jetzt sinnvoll ran? 😉

Man könnte hier jetzt einen Script-Task bauen, der das irgendwohin schreibt, am einfachsten ist das aber über ein spezielles Seitentemplate:

3. Seitentemplate zum Erzeugen der Map

Erstelle ein neues Seitentemplate, z.B. "url_map" mit der Dateiendung ".json" und folgender Ausgabe:

$CMS_IF(!#global.preview && #global.scheduleContext.getProperty("gv_urlMap")!=null)$

    $CMS_VALUE(#global.scheduleContext.getProperty("gv_urlMap").toJSON())$  

$CMS_END_IF$

Erstelle dazu - am besten jeweils "außerhalb" der Website-Ordner - eine Inhaltsseite basierend auf diesem Template und eine Seitenreferenz und gib beides frei.

4. Map im Auftrag erzeugen

Füge dem Generierungsauftrag einen weiteren Generierungstask NACH allen anderen hinzu:

Typ: Teilgenerierung, einziger Startknoten ist die in (4.) angelegt Seitenreferenz.

Wichtig: Nur in EINER Sprache (egal welche) und nur für EINEN (egal welcher) Ausgabekanal erzeugen. Zum Generierungszeitpunkt liegen ja schon alle Infos in der Map.

5. Generieren

Nach dem Generieren (im Auftrag) hast Du dann eine weitere Datei im JSON-Format, die diese Map mit den ganzen Infos enthält. Wenn Du nicht willst, dass sie deployt wird, kannst Du den entsprechenden Generierungstask einfach hinter den Deployment-Task packen.

Viele Grüße

Michael

View solution in original post

8 Replies
mbergmann
Crownpeak employee

Hallo Udo,

ich würde hier grundsätzlich einen anderen Ansatz versuchen: Während der Generierung kann jede Seite ihre eigene URL (=Dateiname) in eine "passende" Datenstruktur - wohl eine (ggf. verschachtelte) Map - legen. Diese Map "lebt" im ScheduleContext (als Property). Nach der Generierung kann man dann im selben Auftrag mit einem weiteren Task diese Map auswerten / ausgeben / whatever.

Dein Ansatz funktioniert wahrscheinlich nicht im Fall von URL-Konflikten und hört sich außerdem irgendwie kompliziert an...

Viele Grüße

Michael

Hallo Michael,

vielen Dank für deine Antwort. Ich gebe dir Recht, dass mein gewählter, hier geschilderter Weg ziemlich umständlich ist. Es war aber aus meinem Verständnis heraus die praktikabelste Lösung um *nach* der Generierung herauszufinden, mit welcher Kombination von Eigenschaften (Sprache, Ausgabetemplate) eine im Generierungsverzeichnis vorgefundene Datei erstellt worden ist.

Die von dir angesprochene Möglichkeit hat unter anderem den Vorteil, dass ich die Dateinamensgenerierung per UrlCreator nur einmal durchführen müsste. Allerdings ist mir nicht ganz klar, wie "jede Seite" ihre eigene URL zum einen während der Generierung unabhängig vom verwendeten UrlCreator herausfinden und speichern kann und wie das insbesondere bei Projektionen und Dokumentengruppen funktioniert.

Vielleicht kannst du mir mit ein paar gezielten Hinweisen hier auf die Sprünge helfen. Das wäre großartig!

Viel Grüße,

Udo.

0 Kudos

Hallo Udo,

vorweg: beschrieben mag sich das Ganze recht aufwändig anhören, ist aber in 30 Minuten gebaut.

1. Füge im Ausgabekanal des Projekteinstellungs-Templates folgendes hinzu:

$CMS_IF(!#global.preview && #global.scheduleContext.getProperty("gv_urlMap")==null)$  

    $CMS_SET(void,#global.scheduleContext.setProperty("gv_urlMap",{:}))$

$CMS_END_IF$

Hintergrund: Der Ausgabekanal der Projekteinstellungen wird zwar nicht "ausgegeben", aber zu Beginn jeder Generierung ausgewertet - und zwar pro Sprache und Ausgabekanal. Dieser Code legt eine leere Map in die Property "gv_urlMap" des Generierungskontextes. Diese Properties "leben" im Auftrag. Vor allem über mehrere Tasks im Auftrag. Nach Ausführung des Auftrages werden sie entsorgt.

2. Rendertemplate

Erstelle ein Rendertemplate (=Formatvorlage, z.B. "save_url_map") mit folgendem Inhalt:

$CMS_IF(!#global.preview && #global.scheduleContext.getProperty("gv_urlMap")!=null)$

    $CMS_SET(set_infoMap,{

        "nodeUid":#global.node.uid,

        "lang":#global.language.abbreviation,

        "templateSet":#global.templateSet.uid,

        "datasetTable":#global.dataset.entity.entityType.name,

        "datasetId":#global.dataset.entity.id

    })$

    $CMS_SET(set_url)$$CMS_REF(#global.ref, abs:2)$$CMS_END_SET$

    $CMS_SET(void,#global.scheduleContext

        .getProperty("gv_urlMap")

        .put(set_url.toString,set_infoMap)

    )$

$CMS_END_IF$

Die infoMap kannst Du nach Deinen Bedürfnissen anpassen, im Beispiel landen darin die UID der Seitenreferenz, die Sprache usw. Es muss nicht unbedingt eine Map sein. Du kannst auch das gv_urlMap bei Bedarf als Liste statt Map nutzen - je nachdem was am praktikabelsten ist. Da ich es aber so verstanden habe, dass Du zu den einzelnen Dateien diese Infos brauchst, macht eine Map mit den absoluten URLs als Keys hier wahrscheinlich am meisten Sinn.

Dieses Rendertemplate bindest Du in alle Seitenvorlagen ein (die Stelle ist relativ egal):

$CMS_RENDER(template:"save_url_map")$

Bis hierher hast Du also nach der Generierung eine Map mit den absoluten Pfaden als Key und einigen Infos als "Sub-Map". Diese Map "lebt" als Property im ScheduleContext.

Die Frage ist: Wie kommt man da jetzt sinnvoll ran? 😉

Man könnte hier jetzt einen Script-Task bauen, der das irgendwohin schreibt, am einfachsten ist das aber über ein spezielles Seitentemplate:

3. Seitentemplate zum Erzeugen der Map

Erstelle ein neues Seitentemplate, z.B. "url_map" mit der Dateiendung ".json" und folgender Ausgabe:

$CMS_IF(!#global.preview && #global.scheduleContext.getProperty("gv_urlMap")!=null)$

    $CMS_VALUE(#global.scheduleContext.getProperty("gv_urlMap").toJSON())$  

$CMS_END_IF$

Erstelle dazu - am besten jeweils "außerhalb" der Website-Ordner - eine Inhaltsseite basierend auf diesem Template und eine Seitenreferenz und gib beides frei.

4. Map im Auftrag erzeugen

Füge dem Generierungsauftrag einen weiteren Generierungstask NACH allen anderen hinzu:

Typ: Teilgenerierung, einziger Startknoten ist die in (4.) angelegt Seitenreferenz.

Wichtig: Nur in EINER Sprache (egal welche) und nur für EINEN (egal welcher) Ausgabekanal erzeugen. Zum Generierungszeitpunkt liegen ja schon alle Infos in der Map.

5. Generieren

Nach dem Generieren (im Auftrag) hast Du dann eine weitere Datei im JSON-Format, die diese Map mit den ganzen Infos enthält. Wenn Du nicht willst, dass sie deployt wird, kannst Du den entsprechenden Generierungstask einfach hinter den Deployment-Task packen.

Viele Grüße

Michael

Großartig! Vielen Dank.

Ich werde die Ideen so schnell wie möglich mit meinem Projekt verküpfen und melde mich dann wieder!

Danke nochmals und herzliche Grüße,

Udo Woitek.

0 Kudos

Hallo Michael,

ich habe deine Vorschläge jetzt mal eingebaut und bin begeistert. Diese Vorgehensweise erspart mir eine Menge Aufwand. Ich hoffe nur, dass der Speicherbedarf nicht exorbitant anwächst, so dass ich diese Methode auch bei größeren FirstSpirit-Projekten anwenden kann. Zur Not werde ich wohl ein paar von den Angaben in der Map reduzieren müssen.

Ich bedanke mich vielmals für die tatkräftige Untersützung.

Schöne Grüße,

Udo Woitek.

0 Kudos

Hallo Udo,

klar, dadurch dass die Map im Speicher gehalten wird ist das natürlich theoretisch möglich. Würde ich jetzt aber aus dem Bauch heraus erstmal einfach probieren - man kann sich den Speicherbedarf ja auch grob ausrechnen. Wieviele Dateien generiert ihr denn so pro Lauf? Falls es damit tatsächlich Probleme gibt, kann man das Ganze auch etwas anders lösen, indem man sich eine eigene Klasse hierfür baut und die aus dem Template-Kanal heraus anspricht. Das wäre aber dann wieder aufwändiger.

Wenn man mal so 200 Bytes pro Eintrag rechnet käme man bei 10.000 Seiten auf schlappe 2MB.

Viele Grüße

Michael

0 Kudos

Hallo Michael,

da wir für externe FirstSpirit-Anwender entwickeln, ist der gesamte Datenbestand nicht sicher. Es könnten aber schon große Webauftritte werden. Aber du hast Recht, es lässt sich ganz gut ausrechnen, was an Datenaufkommen zu erwarten ist. Ich werde mit dieser Lösung erstmal weiter arbeiten und mir die kompliziertere vorbehalten. Nochmals vielen Dank!

Viele Grüße,

Udo.

0 Kudos

Hallo Michael,

die Lösung funktioniert sehr gut. Gibt es denn ein ähnliches Vorgehen für Mediendateien, welche ja sprachunabhängig oder in verschiedenen Generierungssprachen vorliegen können und nicht über Vorlagen für die Ausgabe verfügen?

Danke und viele Grüße,

Udo.

0 Kudos