cardo.Button2
Das Modul cardo.Button wurde für cardo4 völlig neu geschrieben. Die bisherigen Ansätze mit XML/XSD wurden durch einen Mix aus GeoSQL/Scriban/Markdown ersetzt.
Die beiden Module koexistieren, eine automatische Übernahme der Pläne ist nicht möglich.
cardo.Button ist dabei als eigene, interaktiv zu startende, Anwendung verfügbar und auch als "Engine", die von cardo Anwendungen eingebunden werden kann.
Objekte
Plan-Definition
Der Begriff "Plan" ist Nutzern des Moduls bekannt und wird hier weiterverwendet. Ein "Plan" beschreibt die Ausführung von Datenabfragen und auch die Formatierung der Ausgabe.
cardo.Button gibt nicht direkt die Speicherorte von Plänen vor. Diese können bspw. im Dateisystem oder auch in einem anwendungsintegrierten "Wilma" abgelegt werden.
Ein Plan im neuem cardo.Button ist dabei ein einfaches Textdokument, welches mit der cardo Template-Engine, die seinerseits auf Scriban basiert, gelesen wird.
Als Besonderheit gilt die Konvention, dass am Anfang der Datei die Metadaten zu dem Plan hinterlegt werden müssen. Dabei handelt es sich um ein JSON-Objekt vom Typ IButtonPlanDefinition, welches in einem Kommentar-Block am Anfang stehen muss. Hierzu ein einfaches Beispiel.:
{{## { title:"Mein erster Plan", args:{ "tableName":{ title:"Name der Tabelle", type:"Text", isRequired:true } } } ##}}
Ergebnisse der Plan-Ausführung
Ein Plan kann eine Liste von Ergebnissen liefern. Grundlegend sind folgende Typen vorgesehen:
- Text (HTML, oder PlainText)
- Instanz eines cardo Wellknowntype (interaktive Datentabelle, nur in der cardo Umgebung nutzbar)
- PDF Dokument
Daten (JSON)Daten (XML)
In cardo gibt es eine Ausgabekomponente, die den Antworttyp auswertet und eine entsprechende Oberfläche dafür generiert.
Durchgestrichen dargestellte Formate sind geplant, aber noch nicht implementiert.
"BO"
Wie bei allen über die cardo Template-Engine verwendeten Techniken gibt es diverse Erweiterungen die bereitgestellt werden (z.B. uxGeo ...) und das Business-Objekt, kurz "BO", welches immer zur Verfügung steht.
Das "BO" in Button enthält selber keine Daten, stellt aber Eigenschaften und Methoden zur Interaktion mit der Plan-Ausführung zur Verfügung.
Eigenschaften
"TableRowLimit" (10.000)
BO.TableRowLimit = number | null
Das generelle Zeilenlimit für Datenabfragen. Der Standardwert ist 10.000. Wird das Limit erreicht, wird der Plan mit einem Fehler abgebrochen.
"Args"
BO.Args = readonly IDictionary<object>
Hier sind alle im Plan definierten "args" streng typisiert hinterlegt. Die Werte werden vor der Ausführung entsprechend der Plan-Definition validiert und ggf. konvertiert.
"Format"
BO.Format = readonly Types.OutputFormat
Wenn der Plan mehrere Ausgabeformate definiert hat, ist hier das aktuell ausgewählte Format hinterlegt.
"StringContentInterpretation" (PlainText)
BO.StringContentInterpretation = "PlainText" | "Markdown"| "Html" | "DocumentParts" |"None"
Legt fest, wie die Textausgabe des Templates interpretiert wird. Mögliche Werte:
PlainText: Text wird HTML-Encodeded zurückgeliefert, Umbrüche als br
Markdown: Text wird von einem Markdown-Converter in HTML konvertiert
Html: Text wird unverändert zurückgeliefert
DocumentParts: Das Ergebnis enthält unsere IDU spezifische Dokumentauszeichnungen und wird zu einem PDF Dokument konvertiert.
None: Die Textausgabe des Plans wird ignoriert.
Methoden
"DbSQL()"
BO.DbSQL(dbAlias: string) : ISQLBuilderBase
Gibt die Instanz eines Datenbank-Abfrage-Objektes zurück, initialisiert mit einer Datenbankverbindung aus den cardo Einstellungen.
Die Datenbankverbindung muss dabei mit dem Attribut "ButtonDataSource" versehen sein.
Die Datenbankverbindung wird mit dem Aufruf der Methode erstellt und beim Beenden des Plans automatisch geschlossen.
Sie sollten hier Datenbankverbindungen anlegen, mit einem Benutzer mit möglichst wenigen Berechtigungen.
Methode "GeoSQL()"
BO.GeoSQL() : ISQLBuilderBase
Gibt die Instanz eines Datenbank-Abfrage-Objektes zurück, hier immer mit Iwan7 als Datenquelle (GeoSQL Abfragen). Gegenüber der DbSQL Instanz ist hier noch zusätzlich die Methode MapLayerTagsToLayerName verfügbar.
Datenabfragen (ISQLBuilderBase)
Abfragen können aus Datenbanken oder über Iwan7 GeoSQL erfolgen.
Für das Ausführen der Abfragen wird ein Objekt bereitgestellt (BO.DbSQL und BO.GeoSQL), welches Parameter in Abfragen ermöglicht und über sichere Hilfsfunktionen zum Konstruieren von Abfragen bereitstellt.
Wichtig: Setzen Sie nie Abfragen direkt mit vom Benutzer vorgegeben Werten zusammen. Sie ermöglichen sonst Sicherheitsprobleme aus dem Bereich SQL-Injection
Die wesentlichen Methoden diese Objektes sind:
Generieren von Prädikaten (Vergleichen), setzten der Werte als Parameter. Die unten stehenden Methoden haben jeweils die Signatur
op(columName:string, value:object) : string
Zurückgeliefert wird dabei ein Fragment, welches in der Abfrage eingesetzt werden kann. I.d.R. wird dazu ein Datenbank-Parameter erstellt und in dem Abfrageobjekt hinterlegt.
Der Spaltenname wird durch die Methode nicht extra behandelt. Sollte es sich beim dem Namen um einen Benutzerwert handeln, verwende unbedingt die Methode
QuoteIdent()
.Folgende Prädikate gibt es derzeit:
EQ(colName:string, value:object) : string
IN(colName:string, values:object[]) : string
LIKE(colName:string, value:string) : string
ILIKE(colName:string, value:string) : string
INTERSECTS(colName:string, geometryValue:object) : string
Einfügen von Parametern, setzten eines Wertes als Parameter, zurückliefern des Platzhalters in der Abfrage
AddParam(value:object) : string
AddParamGeom(geometryValue:object) : string
Allgemeine Hinweise zu Parametern
- Bei Iwan7 werden keine Parameter verwendet, es wird aber garantiert, dass die Werte mit GeoSQL kompatibel sind und korrekt maskiert werden.
- Werte vom Typ Geometrie werden verschiedenen Formaten interpretiert, bspw. EWKT, GML, oder als echtes Geometrie-Objekt
Maskieren von Objektnamen
Die Methode
QuoteIdent(ident: string, allowMultiPart:bool = false) : string
maskiert den Identifikator (Tabellenname etc., Spaltenname) bei Bedarf entsprechend der Regeln der zugrunde liegenden Datenbank und sollte immer verwendet werden, wenn Teile der Abfrage aus Benutzereingaben stammt.allowMultiPart
gibt dabei an, ob mehrteilige Bezeichner erwartet werden (bspw.: "Schema"."Tabelle").Ausführen der Abfrage
Die Datenabfrage wird mit einer der Execute** Methoden ausgeführt. Nach dem Ausführen werden die evtl. zuvor hinzugefügten Parameter wieder entfernt.
Beachte auch die Eigenschaft
BO.TableRowLimit
Die Methoden unterscheiden sich im Generieren der Rückgabe.
ExecuteStoreResult(sql: string) : void
Hier wird das Ergebnis direkt als Objekt vom Typ
cardo.Core.WellKnownType.TableData
in dem Plan hinterlegt, ein Zugriff auf die Ergebnisse aus dem Plan heraus ist nicht vorgesehen.Eine bereits zuvor abgespeichertes Ergebnisobjekt wird durch dieses ersetzt.
In cardo wird diese Tabelle dann mit der bekannten Tabellenansicht angezeigt.
ExecuteAsTable(sql: string) : PiB.Presentation.TemplateEngine.ux.TableSnapshotResult
Hier wird ein Snapshot der Tabelle erstellt und an das Script des Plans zur weiteren Verarbeitung zurückgegeben.
Nur GeoSQL: Layernamen anhand eines Alias ermitteln
MapLayerTagsToLayerName(src: IDictionary<string>, errorWhenNotFound:boolean = true) : IDictionary<string>
In dieser Methode wird in src ein Objekt übergeben, der Key ist ein selber vergebener Name, der Wert des "Alias" einer Ebene im cardo Themenbaum.
Das Ergebnis enthält dann in value zu dem gleichen Key den ermittelten Ebenennamen oder null, wenn zu dem Alias kein Name ermittelt werden konnte (wenn errorWhenNotFound mit false übergeben wurde, sonst kommt in diesem Falle eine Fehlermeldung).
Anhang
Typdefinitionen
IButtonPlanDefinition
/**
* Definition eines Argumentes für einen Report
*/
export interface IButtonArgumentMetadata
{
/**
* Der Anzeigename, nicht optional
*/
title: string;
/**
* Beschreibung, optional
*/
htmlDescription?: string | null;
/**
* Der technische Datentyp
*/
type: IduIT.GeoLib.Core.DataTypeType;
/**
* Eine Liste von Werten
*/
isArray: boolean;
/**
* Gibt an, ob dieses Argument optional ist
*/
isRequired: boolean;
/**
* Wenn != null, dann eine Werteliste generieren (Label+Value)
*/
lookupRecords?: IduIT.Core.Data.Lookup.ILookupRecord[] | null;
}
/**
* Definition eines "Reports" / ButtonPlan
*/
export interface IButtonPlanDefinition
{
/**
* Die innerhalb der Implementierung der ButtonEngineBase eindeutige Kennung.
*/
reportId: string;
/**
* Liste von Gruppen/Nutzer, für die das sichtbar ist
*/
visibleFor?: string[] | null;
/**
* Mögliche Ausgabeformate
*/
formats?: IduIT.cardo.Core.CoreModules.Button.Types.OutputFormat[] | null;
/**
* Der Anzeigename, nicht optional
*/
title: string;
/**
* Beschreibung, optional
*/
htmlDescription?: string | null;
/**
* Argumente, die zum Starten (erforderlich) sind
*/
args?: IDictionary<IduIT.cardo.Core.CoreModules.Button.Types.IButtonArgumentMetadata> | null;
}
/**
*/
export enum OutputFormat
{
/**
*/
Default = 0,
/**
*/
TextPlain = 1,
/**
*/
Html = 2,
/**
*/
JSON = 3,
/**
*/
PDF = 4,
/**
*/
NativeCardoType = 5,
}
Beispiel-Plan
{{##
{
title:"Test-Plan",
htmlDescription:null,
formats:["PDF","Html","NativeCardoType"],
args:{
"tableName":{
title:"Name der Tabelle",
htmlDescription:"",
type:"Text",
isArray:false,
isRequired:true
}
}
}
##}}
{{
BO.StringContentInterpretation = "Markdown"
$sqlBld = BO.GeoSQL();
$sql = $"
SELECT
*
FROM
{$sqlBld.QuoteIdent(ident:BO.Args.tableName,allowMultiPart:true)}
WHERE
{$sqlBld.EQ("numcol",1)}
OR col = {$sqlBld.AddParam(1)}
OR {$sqlBld.EQ("str","Test")}
OR {$sqlBld.EQ("str",null)}
OR {$sqlBld.EQ("bool",true)}
OR {$sqlBld.EQ("bool",false)}
OR {$sqlBld.IN("lst",["a","b"])}
OR {$sqlBld.LIKE("lst","%test")}
OR {$sqlBld.LIKE("lst","t%t")}
OR {$sqlBld.ILIKE("lst",["a","b"])}
OR {$sqlBld.INTERSECTS("geom","srid=4326;POINT(5 5)")}
"
$sql
}}
Zuletzt geändert: 12.05.2025 12:47:11 (erstmals erstellt 27.03.2025) // Alias: "Button2"