backgroundimage

marbetschar - Coldfusion, Klettern, Freizeit

FW/1 2.0 Stable!

2

Bereits seit einiger Zeit als Release Candidate verfügbar, hat FW/1 nun den goldenen Sprung geschafft und ist in der finalen Version 2.0 zum Download verfügbar! Vielen dank Sean Corfield!

Bleibt jetzt nur noch abzuwarten wie lange es dauern wird bis DI/1 erwachsen wird!? Ich hoffe, dass dies auch bald geschehen wird!

Download Webseite
Mehr lesen Kategorien: ColdFusion

blade Plugin Template

0

Heute bin ich über etwas sehr erfreuliches gestolpert: Das Template für mura Plugins auf blade Basis ist nun im offiziellen mura Marketplace zum Download verfügbar!

Ich möchte an dieser Stelle einen grossen Dank an Reinhard Jung aussprechen, der mich mit Rat und Tat unterstützt hat.

Und allen anderen wünsche ich: Happy Plugin Coding! :)

NACHTRAG: Der Download Link scheint zurzeit nicht zu funktionieren - das mura Team ist bereits informiert und wird diesen Fehler hoffentlich bald bereinigen.

Download
Mehr lesen Kategorien: ColdFusion

Introduction to blade

8

There are quite a few other application frameworks for ColdFusion out there, so why write another one? This is a very good question and in this blog post i’ll try to give you an answer and a brief overview of blade.

Why write another application framework?

I like the way how conventions work. There are a few rules you have to follow and behind the scenes the magic will happen. That’s why i really love FW/1. No need to write Xml configuration files such as in ModelGlue nor read over 600 pages of documentation such as in ColdBox. Just place your controllers in the controllers and the services in the services directory. It couldn’t be easier!

However, there are some things which FW/1 have not built in, since FW/1 is a small, lightweight MVC framework. Nothing more. BUT: The real worlds weight is far from “light”. So i’ve been digging around for an existing application framework but have nothing found which suite my needs of

  • MVC
  • built in ColdFusion ORM
  • BeanFactory
  • Validation
  • convention based
  • easy to learn and use
  • rapid development

I think the only way to go before blade was cfWheels. But I don’t like how cfWheels pushes you to over-simplify your code (such as scopeless variables).

Overview of blade

Installation

Download the zip file from RIAForge und unpack it. You will get three different directories:

  • blade (the application framework - see description below)
  • samples (sample applications)
  • skeleton (an empty application skeleton)

To install blade, copy the blade directory to your webroot.

The Framework

  • hyrule (the hyrule validation framework)
  • org (FW/1)
  • wirebox (the WireBox IoC framework)
  • Application.cfc
    The Application.cfc extends Sean Corfield’s FW/1, adds the BeanFactory and some functionality for validation purposes. You have to extend this CFC instead of FW/1.
  • Binder.cfc
    The Binder.cfc is used from within the Application.cfc and configurates WireBox how load your beans, controllers, models and services.
  • Injector.cfc
    The Injector.cfc adds the getBean() and containsBean() method to the WireBox Injector. Those methods are needed by FW/1.
  • Model.cfc
    The Model.cfc is a Wrapper for all ColdFusion ORM functions and your model cfc’s have to extend this object. This Wrapper adds the ability to inject any objects into your model cfc’s.
  • ValidationResult.cfc
    The ValidationResult.cfc is needed by the Application.cfc to simplify the validation process.
  • mappings.cfm
    You will have to cfinclude this file into your Application.cfc. It will create the mappings for the frameworks used inside of blade.

How to load blade

To load blade, just extend the blade.Application class and cfinclude the mappings.cfm:

<cfcomponent output="false" extends="blade.Application" hint="Applikationskomponente">
  <cfinclude template="/blade/mappings.cfm" />
</cfcomponent>

See the FW/1 docs for a deeper look into the framework configuration. Please note, that the setupApplication and the setupSubsystem functions are used by blade. So if you want to customize these, make sure you call super.setupApplication() or super.setupSubsystem(argumentCollection=arguments) from within them first:

<cffunction name="setupApplication" returntype="void" access="public" output="false" hint="Wird beim Applikationsstart ausgeführt">
  <cfset super.setupApplication() />
  ... do your own stuff ...
</cffunction>

The “model” directory

blade automatically threat all (not recursive!) of your objects in the “model” directory as transients. So you have the ability to store all of your ColdFusion ORM entities in this folder. Please make sure your entity objects extend the base model class of blade.

<cfcomponent accessors="true" output="false" persistent="true" extends="blade.Model" hint="Model">
...
</cfcomponent>

If you wan’t to inject a model cfc, just inject it with the id “cfcNameModel”.

<cfproperty name="userModel" inject="id:userModel" />

The “beans” directory

All of your objects in the “beans” directory will be recursively loaded and WireBox will store them as singletons. If you wan’t to inject your bean objects into your controllers, services, or model cfc’s please note, that the id of the object will be the reverted path inside of the beans directory. A bean called “profileChar” which is stored inside of the beans/util directory will get the id “profileCharUtil”.

  • beans
    • util
      • profilechar.cfc
<cfproperty name="profileChar" inject="id:profileCharUtil" />

That’s it! For a deeper look into the framework, see the samples directory of the download.

Mehr lesen Kategorien: ColdFusion

mura: Content Search im öffentlichen Bereich

0

mura ist ein tolles open source cms auf basis von ColdFusion. Es lässt sich kinderleicht erweitern, bringt aber auch die wichtigsten Funktionen freihaus mit. Deshalb dachte ich mir, eine einfache Suche im Webauftritt muss doch ebenfalls mitgeliefert worden sein?!

Leider wurde ich im Netz aber nicht fündig. Ihr könnt euch denken warum: Die Lösung ist viel zu einfach. Deshalb hat sich niemand die Mühe gemacht um einen Blogeintrag zu erstellen: Es reicht, wenn man die index.cfm mit folgenden Parametern aufruft:

/index.cfm?display=search&amp;keywords=searchString

Natürlich benötigt man in der Regel ein Formular, aber auch das ist nicht allzu kompliziert. Ausserdem lassen sich der Suche weitere Parameter mitgeben:

&lt;form id="searchForm" action="#cgi.script_name#"&gt;
   &lt;input type="hidden" name="display" value="search" /&gt;
   &lt;input type="hidden" name="newSearch" value="true" /&gt;
   &lt;input type="text" name="keywords" value="" /&gt;
   &lt;input type="submit" class="formbtn" value="Search" /&gt;
&lt;/form&gt;

Welche Parameter alle übergeben werden können, weiss ich noch nicht. Ich werde mir das noch einmal genauer anschauen.

Leichtgewichtige BeanFactory für Dependency Injection und IoC

0

Bei meinen letzten Projekten kam der Wunsch nach einer sehr einfach gehaltenen BeanFactory auf. Diese Factory sollte ebenfalls einige einfachen Dependency Injection Funktionalitäten mitbringen und keine zusätzlichen Konfigurationen benötigen. Das Resultat möchte ich euch hier gerne Vorstellen.

Die BeanFactory besteht aus einer einzigen CFC und besitzt folgende Features:

  • Laden von Beans anhand eines Class-Paths
  • Aufruf der init-Methoden der Beans
  • Automatische Verknüpfung der verschiedenen Beans mithilfe von Getter- und Setter-Methoden
  • Aufruf der setup-Methode für weiterführende Initialisierung (falls Daten aus anderen Beans geladen werden müssen)
  • Unterstützung von mehreren Factories mithilfe von setParent()

Damit die Factory richtig funktioniert, muss im Application.cfc ein Mapping zum Class-Path angelegt werden:

&lt;cfset this.mappings['/my'] = '#getDirectoryFromPath(getCurrentTemplatePath())#my' /&gt;

Um mehrere Beans untereinander zu verknüpfen, müssen jeweils Accessoren mit dem Beannamen vorhanden sein. Die Getter- und Setter-Methoden lassen sich seit ColdFusion 9 automatisch generieren.

&lt;cfcomponent accessors="true"&gt;

&lt;cfproperty name="profilechar" hint="ProfileChar Bean" /&gt;
&lt;cfproperty name="localization" hint="Localization Bean" /&gt;

...

Um die Factory zu laden, muss beim Applikationsstart lediglich die init-Methode ausgeführt und ihr der classPath übergeben werden.

&lt;cfset application.factory = new factory(classPath='my.class.path') /&gt;

Sind die Beans erst einmal geladen, können sie mithilfe von containsBean(‘beanName’) und getBean(‘beanName’) während der Laufzeit aus der Factory geholt werden.

Die BeanFactory steht zum Download zur Verfügung.

Mehr lesen Kategorien: ColdFusion

getPageContext().getFusionContext(): Mappings und Application-Root-Path auslesen

0

Eines der grossen und unerforschten Objekte in der ColdFusion Welt ist der NeoPageContext. Bei richtiger Anwendung kann er aber sehr wertvolle Informationen wie den Application-Root-Path oder alle Applikationsspezifischen Mappings liefern und dies unabhängig von wo er aufgerufen wird.

Folgende Zeile liefert den Application Root:

&lt;cfset local.appRoot = getPageContext().getFusionContext().getApplicationPath() /&gt;

Und folgendes liefert die Applikationsspezifischen Mappings als Struktur (wie mit this.mappings innerhalb der Application.cfc):

&lt;cfset local.mappings = getPageContext().getFusionContext().getApplicationCustomMappings() /&gt;
Mehr lesen Kategorien: ColdFusion

Kombipaket für schnelle und gute Applikationsentwicklung

0

Es gibt unzählbar viele Frameworks. Alle haben ihre Vor- und Nachteile. Das ist auch in der ColdFusion Welt nicht anders. Immer wieder taucht die gleiche Frage auf: Welches Framework ist das beste für die Entwicklung mit ColdFusion?

Anstatt sich zu fragen welches Einzelframework am besten geeignet ist, sollte man sich überlegen welche Kombination von Frameworks die Beste ist.

Auf der Suche nach Informationen in diesem Bereich bin ich über die cfcommons gestolpert. Das Framework sieht sehr spannend aus. In Kombination mit FW/1 von Sean Corfield, ORM und vielleicht Hyrule von Dan Vega könnten sehr interessante Applikationen entstehen.

Werde in nächster Zeit eine kleine Beispielapplikation mit genannten Frameworks erstellen.

Mehr lesen Kategorien: ColdFusion

HQL Queries und ORM Properties: Kompromiss

0

Wie bereits in einem vorherigen Beitrag erwähnt, handhabt Hibernate HQL Queries unter Berücksichtigung der Gross/Kleinschreibung. Der Nachteil dieses Fakts bekahm ich gestern zu spüren als ich einige Funktionen programmierte, die Blogeinträge auslesen sollten.

Die Funktionalität die umgesetzt werden sollte, war ein guter alter Pageturner: Es werden maximal 10 Eintäge auf der Startseite angezeigt werden und durch Links kann man vor- und zurückblättern.

&lt;cfif local.offset&gt;
	&lt;p&gt;&lt;a href="#buildURL('blog.entries#local.queryString#&amp;offset=#local.offsetNewer#')#" title="neuere"&gt;neuere&lt;/a&gt;&lt;/p&gt;
&lt;/cfif&gt;

&lt;cfif local.entryCount GT local.offsetOlder&gt;
	&lt;p&gt;&lt;a href="#buildURL('blog.entries#local.queryString#&amp;offset=#local.offsetOlder#')#" title="ältere"&gt;ältere&lt;/a&gt;&lt;/p&gt;
&lt;/cfif&gt;

Um die Links korrekt ein- und ausblenden zu können, soll die komplette Anzahl Links (der local.entryCount) anhand der übergebenen Parameter ermittelt werden. Es gibt also zwei Funktionen im Service: Eine list und eine count Funktion - beide machen eigentlich dasselbe:

&lt;cffunction name="count" returntype="numeric" access="public" output="false" hint="Zählt die Anzahl Einträge"&gt;

	&lt;cfset local.ormResult = executeQuery(executionMode='count',argumentCollection=arguments) /&gt;

	&lt;cfset local.result = 0 /&gt;
	&lt;cfif arrayLen(local.ormResult)&gt;
		&lt;cfset local.result = local.ormResult[1] /&gt;
	&lt;/cfif&gt;

	&lt;cfreturn local.result /&gt;
&lt;/cffunction&gt;

&lt;cffunction name="list" returntype="array" access="public" output="false" hint="Liest Einträge aus"&gt;
	&lt;cfreturn executeQuery(executionMode='default',argumentCollection=arguments) /&gt;
&lt;/cffunction&gt;

Die Magie geschieht in den executeQuery und prepareHQL Methoden. Diese parsen als erstes die argumentCollection und führen das HQL - Query aus.

&lt;cffunction name="executeQuery" returntype="array" access="private" output="false" hint="Führt ein HQL Query aufgrund der übergebenen Argumente aus"&gt;
	&lt;cfargument name="executionMode" type="string" required="false" default="default"	hint="Welche Art von Query ausgeführt werden soll: count, default, search" /&gt;

	&lt;cfset local.hql = prepareHQL(argumentCollection=arguments) /&gt;

	&lt;cfreturn ormExecuteQuery(local.hql.statement,local.hql.args,false,local.hql.options) /&gt;
&lt;/cffunction&gt;


&lt;cffunction name="prepareHQL" returntype="struct" access="private" output="false" hint="Generiert das HQL Statement"&gt;
	&lt;cfargument name="executionMode"		type="string"		required="false"	default="default"	hint="Welche Art von Query ausgeführt werden soll: count, default" /&gt;
	&lt;cfargument name="search"						type="string"		required="false"	default=""	hint="Freitext nach dem gesucht werden soll" /&gt;
	&lt;cfargument name="ident"						type="guid"			required="false"	hint="Schlüssel des Eintrags" /&gt;
	&lt;cfargument name="isActive"					type="boolean"	required="false"	hint="Ob der Eintrag aktiv ist" /&gt;
	&lt;cfargument name="Title"						type="string"		required="false"	hint="Titel des Eintrags" /&gt;
	&lt;cfargument name="urlTitle"					type="string"		required="false"	hint="Url sicherer Titel" /&gt;
	&lt;cfargument name="Teaser"						type="string"		required="false"	hint="Einleitung des Eintrags" /&gt;
	&lt;cfargument name="Body"							type="string"		required="false"	hint="Inhalt des Eintrags" /&gt;
	&lt;cfargument name="Download"					type="string"		required="false"	hint="Downloadlink" /&gt;
	&lt;cfargument name="Website"					type="string"		required="false"	hint="URL zu einer Webseite" /&gt;
	&lt;cfargument name="GeoLocation"			type="string"		required="false"	hint="Karten URL" /&gt;
	&lt;cfargument name="postedAt"					type="any"			required="false"	hint="Veröffentlichungs-Zeitpunkt" /&gt;
	&lt;cfargument name="postedFrom"				type="any"			required="false"	hint="Ab Veröffentlichungs-Zeitpunkt" /&gt;
	&lt;cfargument name="postedTo"					type="any"			required="false"	hint="Bis Veröffentlichungs-Zeitpunkt" /&gt;
	&lt;cfargument name="postedBy"					type="any"			required="false"	hint="Verfasser" /&gt;
	&lt;cfargument name="joinCategoryArgs"	type="struct"		required="false"	default="#structNew()#"	hint="Bedingungen die auf die verknüpften Kategorien zutreffen müssen" /&gt;
	&lt;cfargument name="orderBy"					type="string"		required="false"	default="postedAt DESC"	hint="Sortierreihenfolge der Resultate" /&gt;
	&lt;cfargument name="offset"						type="numeric"	required="false"	default="0"	hint="Offset ab welchem Einträge geliefert werden sollen" /&gt;
	&lt;cfargument name="maxResults" 			type="numeric" 	required="false"	hint="Maximale Anzahl an Einträgen die ausgelesen werden sollen" /&gt;

	&lt;cfset local.hql.select			= arrayNew(1) /&gt;
	&lt;cfset local.hql.joins			= arrayNew(1) /&gt;
	&lt;cfset local.hql.group			= arrayNew(1) /&gt;
	&lt;cfset local.hql.conditions	= arrayNew(1) /&gt;
	&lt;cfset local.hql.sort				= arrayNew(1) /&gt;
	&lt;cfset local.hql.args				= structNew() /&gt;
	&lt;cfset local.hql.options		= structNew() /&gt;

	&lt;cfset arrayAppend(local.hql.select,'SELECT') /&gt;
	&lt;cfset arrayAppend(local.hql.conditions,'WHERE') /&gt;
	&lt;cfset arrayAppend(local.hql.group,'GROUP BY') /&gt;
	&lt;cfset arrayAppend(local.hql.sort,'ORDER BY') /&gt;

	&lt;cfif arguments.executionMode EQ 'default'&gt;
		&lt;cfloop list="offset,maxResults" index="local.option"&gt;
			&lt;cfif structKeyExists(arguments,local.option)&gt;
				&lt;cfset local.hql.options[local.option] = arguments[local.option] /&gt;
			&lt;/cfif&gt;
		&lt;/cfloop&gt;
	&lt;/cfif&gt;

	&lt;cfset arrayAppend(local.hql.group,'main') /&gt;

	&lt;cfloop list="#arguments.orderBy#" index="local.sort"&gt;
		&lt;cfset arrayAppend(local.hql.sort,lCase('main.#local.sort#')) /&gt;
	&lt;/cfloop&gt;

	&lt;cfloop collection="#arguments#" item="local.arg"&gt;
		&lt;cfif isNull(arguments[local.arg])&gt;
			&lt;cfset structDelete(arguments,local.arg) /&gt;
		&lt;/cfif&gt;
	&lt;/cfloop&gt;

	&lt;cfif arguments.executionMode EQ 'count'&gt;
		&lt;cfset arrayAppend(local.hql.select,'COUNT(main)') /&gt;
	&lt;cfelse&gt;
		&lt;cfset arrayAppend(local.hql.select,'main') /&gt;
	&lt;/cfif&gt;
	&lt;cfset arrayAppend(local.hql.select,'FROM blog_main AS main') /&gt;

	&lt;cfif len(arguments.search)&gt;
		&lt;cfset arrayAppend(local.hql.conditions,'1=1') /&gt;
		&lt;cfif structKeyExists(arguments,'isActive')&gt;
			&lt;cfset arrayAppend(local.hql.conditions,'AND main.isactive = :isactive') /&gt;
			&lt;cfset local.hql.args.isactive = arguments.isActive /&gt;
		&lt;/cfif&gt;

		&lt;cfset arrayAppend(local.hql.conditions,'AND ( 1=2') /&gt;
		&lt;cfset local.hql.args.search = '%#arguments.search#%' /&gt;
		&lt;cfloop list="Title,urlTitle,Teaser,Body,Download,Website,GeoLocation" index="local.local.property"&gt;
			&lt;cfset arrayAppend(local.hql.conditions,'OR main.#lCase(local.property)# LIKE :search') /&gt;
		&lt;/cfloop&gt;
		&lt;cfset arrayAppend(local.hql.conditions,')') /&gt;

	&lt;cfelse&gt;
		&lt;cfset arrayAppend(local.hql.conditions,'1=1') /&gt;

		&lt;cfloop collection="#arguments#" item="local.arg"&gt;
			&lt;cfset local.arg = lCase(local.arg) /&gt;
			&lt;cfswitch expression="#local.arg#"&gt;
				&lt;cfcase value="joincategoryargs"&gt;
					&lt;cfif structCount(arguments.joinCategoryArgs)&gt;
						&lt;cfset arrayAppend(local.hql.joins,'LEFT JOIN main.categories AS cat') /&gt;
						&lt;cfloop collection="#arguments.joinCategoryArgs#" item="local.joinArg"&gt;
							&lt;cfset local.joinArg = lCase(local.joinArg) /&gt;
							&lt;cfswitch expression="#local.joinArg#"&gt;
								&lt;cfcase value="isactive"&gt;
									&lt;cfset arrayAppend(local.hql.conditions,'AND cat.#local.joinArg# = :cat#local.joinArg#') /&gt;
									&lt;cfset local.hql.args['cat#local.joinArg#'] = arguments.joinCategoryArgs[local.joinArg] /&gt;
								&lt;/cfcase&gt;
								&lt;cfcase value="urlboard"&gt;
									&lt;cfset arrayAppend(local.hql.conditions,'AND cat.#local.joinArg# LIKE :cat#local.joinArg#') /&gt;
									&lt;cfset local.hql.args['cat#local.joinArg#'] = '%#arguments.joinCategoryArgs[local.joinArg]#%' /&gt;
								&lt;/cfcase&gt;
							&lt;/cfswitch&gt;
						&lt;/cfloop&gt;
					&lt;/cfif&gt;
				&lt;/cfcase&gt;

				&lt;cfcase value="postedat"&gt;
					&lt;cfif isDate(arguments.postedAt)&gt;
						&lt;cfset local.hql.args.postedat = arguments.postedAt /&gt;
					&lt;cfelse&gt;
						&lt;cfset local.hql.args.postedat = lsParseDateTime(arguments.postedAt) /&gt;
					&lt;/cfif&gt;
					&lt;cfset arrayAppend(local.hql.conditions,'AND main.postedat = :postedat') /&gt;
				&lt;/cfcase&gt;

				&lt;cfcase value="postedfrom"&gt;
					&lt;cfif isDate(arguments.postedFrom)&gt;
						&lt;cfset local.hql.args.postedfrom = arguments.postedFrom /&gt;
					&lt;cfelse&gt;
						&lt;cfset local.hql.args.postedfrom = lsParseDateTime(arguments.postedFrom) /&gt;
					&lt;/cfif&gt;
					&lt;cfset arrayAppend(local.hql.conditions,'AND main.postedat &gt;= :postedfrom') /&gt;
				&lt;/cfcase&gt;

				&lt;cfcase value="postedto"&gt;
					&lt;cfif isDate(arguments.postedTo)&gt;
						&lt;cfset local.hql.args.postedto = arguments.postedTo /&gt;
					&lt;cfelse&gt;
						&lt;cfset local.hql.args.postedto = lsParseDateTime(arguments.postedTo) /&gt;
					&lt;/cfif&gt;
					&lt;cfset arrayAppend(local.hql.conditions,'AND main.postedat &lt;= :postedto') /&gt;
				&lt;/cfcase&gt;

				&lt;cfcase value="postedby"&gt;
					&lt;cfset local.hql.args.postedby = arguments.postedBy /&gt;
					&lt;cfif isSimpleValue(arguments.postedBy)&gt;
						&lt;cfset local.hql.args.postedby = entityLoadByPk('sys_user',arguments.postedBy) /&gt;
					&lt;/cfif&gt;
					&lt;cfset arrayAppend(local.hql.conditions,'AND main.postedby = :postedby') /&gt;
				&lt;/cfcase&gt;

				&lt;cfdefaultcase&gt;
					&lt;cfif listFindNoCase('Ident,isActive,Title,urlTitle,Teaser,Body,Download,Website,GeoLocation',local.arg)&gt;
						&lt;cfset arrayAppend(local.hql.conditions,'AND main.#local.arg# = :#local.arg#') /&gt;
						&lt;cfset local.hql.args[local.arg] = arguments[local.arg] /&gt;
					&lt;/cfif&gt;
				&lt;/cfdefaultcase&gt;
			&lt;/cfswitch&gt;
		&lt;/cfloop&gt;
	&lt;/cfif&gt;

	&lt;cfset local.hql.statement = ' /&gt;
	&lt;cfloop list="select,joins,conditions,group,sort" index="local.part"&gt;
		&lt;cfset local.hql.statement = listAppend(local.hql.statement,arrayToList(local.hql[local.part],' '),' ') /&gt;
	&lt;/cfloop&gt;

	&lt;cfreturn local.hql /&gt;
&lt;/cffunction&gt;

Das Problem welches sich eingestellt hat, ist diese vermaledeite Gross/Kleinschreibung. ColdFusion übergibt Strukturen teilweise Uppercase - da ist natürlich mit camelCase Properties in den persistenten Komponenten Essig.

Die Moral von der Geschichte: lowercase für alle Properties - ausser jemand kennt da ne elegantere Lösung?!

ormExecuteQuery ist case sensitive

0

Bei meinen heutigen Experimenten hat folgender Code eine java.lang.NullPointerException geworfen:

&lt;cfreturn ormExecuteQuery('FROM blog_main WHERE title LIKE :title',{ title='%arguments.title%' }) /&gt;

Die Ausführung folgender Zeile lieferte allerdings das gewünschte Array:

&lt;cfreturn ormExecuteQuery('FROM blog_main WHERE Title LIKE :title',{ title='%arguments.title%' }) /&gt;

Der Unterschied besteht lediglich aus der Schreibweise des Title Attributs. Einfacher Lehrsatz: Hibernate basiert auf Java - Java ist case sensitive.

setPassword oder setUsername mit attributeCollection

0

Viele Dinge lassen sich sehr einfach mit dem neuen ORM von ColdFusion lösen und deshalb macht es richtig Spass damit zu arbeiten.

Da dieses Feature noch ziemlich neu in ColdFusion ist, muss man sich allerdings bei der Arbeit auf einige auf den ersten Blick willkürlich erscheinende Überaschungen gefasst machen.

Heute arbeitete ich mit einem User Model. Einfachheitshalber habe ich dieses auf den Benutzernamen und das Passwort reduziert.

&lt;cfcomponent output="false" persistent="true" hint="Benutzer Model"&gt;

&lt;cfproperty name="ident"			type="guid"			ormType="string"		notNull="true"	getter="true"	setter="false"	length="36"	generator="guid"	fieldType="id"	hint="Eindeutiger Schluessel" /&gt;
&lt;cfproperty name="Username"		type="string"		ormType="string"		notNull="true"	getter="true"	setter="true" 	length="50"		validate="string"	validateParams="{minLength=1,maxLength=50}"	hint="Benutzername des Benutzers" /&gt;
&lt;cfproperty name="Password"		type="string"		ormType="string"		notNull="true"	getter="true"	setter="true" 	length="50"		validate="string"	validateParams="{minLength=1,maxLength=50}"	hint="Passwort des Benutzers" /&gt;

&lt;/cfcomponent&gt;

Die Formulardaten möchte ich automatisch in das Model übernehmen. Das bedeutet konkret, dass die dynamisch durch ColdFusion generierten Setter Methoden für die Attribute ‘username’ und ‘password’ automatisch ausgeführt werden sollen, sofern im Formular die entsprechenden Felder existieren.

Klingt nach einer einfachen Anforderung: Ein loop über die Funktionen des Models und sofern ein entsprechender Setter vorhanden ist wird dieser mit den Formulardaten gefüttert. Die Lösung zur dynamischen ausführung des Setters heisst cfinvoke:

&lt;cfinvoke component="#arguments.entity#" method="#local.ormFunction.name#" attributeCollection="#local.args#" /&gt;

Dem Befehl übergebe ich eine Bereinigte Struktur mit dem getrimmten Formularwert.

Dabei wirft ColdFusion allerdings eine Exception:

The Password parameter to the SETPASSWORD function is required but was not passed in

Was auf den ersten Blick verwirrend aussieht, macht durchaus Sinn wenn man sich die Neuerungen seit CF 8 CFTags mit attributeCollection definieren und das Handbuch zu cfinvoke anschaut.

Vielleicht ist in CF 9.0.1 das Problem ja behoben, die BugID 83671 sieht auf jedenfall vielversprechend aus.

UPDATE: Das Update von CF 9 auf CF 9.0.1 hat nichts gebracht - es ist halt ein Feature, kein Bug… Abhilfe schafft ein nicht ganz so schönes evaluate Statement:

&lt;cfset evaluate("arguments.entity.#local.ormFunction.name#(#local.propertyName#='#local.propertyValue#')") /&gt;

Elegantere Lösungsvorschläge sind jederzeit willkommen…

UPDATE: Wenn man vor lauter Bäumen den Wald nicht sieht. cfinvokeargument heisst das Zauberwort:

&lt;cfinvoke component="#arguments.entity#" method="#local.ormFunction.name#"&gt;
  &lt;cfinvokeargument name="#local.propertyName#" value="#local.propertyValue#" /&gt;
&lt;/cfinvoke&gt;

Damit klappts auch mit dynamischen Settern.

ColdFusion, ORM, Datentypen

0

Bob Silverberg hat einen interessanten Artikel über Typdeklarationen in ColdFusion Entities publiziert. Soweit ich das verstanden habe, ist die bestmögliche Typdeklaration einer Eigenschaft die Kombination aus den type- und ormType-Attributen. Das type-Attribut für ColdFusion, damit die automatisch generierten Setter eine korrekte Typprüfung durchführen können und das ormType-Attribut für Hibernate, damit dieses den korrekten Datentyp für die Datenbankspalten verwendet.

&lt;cfproperty name="content"	type="string"	ormType="text"	notNull="true"	getter="true"	setter="true" hint="Inhalt" /&gt;
Mehr lesen Kategorien: ColdFusion

PDF Templates kombinieren

0

Heute bin ich auf der Arbeit auf eine interessante Möglichkeit gestossen, wie unterschiedliche PDF Dateien kombiniert werden können.

Natürlich lässt sich der cfpdf - Befehl dafür nutzen, nur sind dessen Möglichkeiten doch ziemlich begrenzt.

Einen grösseren Funktionsumfang hat da die von cfpdf benutzte Java Bibliothek iText. Diese lässt sich natürlich auch gleich direkt über ColdFusion ansprechen.

So ist es möglich, mehrere PDF-Templates übereinander zu legen. Mehr dazu im Blogbeitrag.

Mehr lesen Kategorien: ColdFusion

Inversion Of Control: DI/1

0

Einigen ColdFusion Entwicklern sollte der Begriff Inversion Of Control im Zusammenhang mit ColdSpring ein Begriff sein.

Leider verwendet ColdSpring Xml-Konfigurationen. Das bedeutet, dass die Arbeit bei der Verwendung von ColdSpring nicht gerade abnimmt. Allerdings tut sich Interessantes aus der FW/1 Ecke: Sean Corfield hat das Problem erkannt und sich daran gemacht selbst eine Bean Factory zu schreiben. Der aktuelle Stand kann auf github eingesehen werden.

Da bin ich mal gespannt wie ein Flitzebogen!

Mehr lesen Kategorien: ColdFusion

plugins in FW/1: pluginMan

1

Es gibt wiederkehrende Aufgaben die Applikationsübergreifend gelöst werden können. Ein gutes Beispiel dafür sind Übersetzungen oder ein Syntaxhighlighting.

Idealerweise kann der erstellte Code 1:1 in eine andere Applikation eingebunden werden.

Um genau solchen Code erzeugen zu können, habe ich den pluginMan für eine Framework One Applikation erstellt.

Diese Blog Engine läuft bereits auf Basis von Framework One mit einem Übersetzungs- respektive Syntaxhighlighting-Plugin.

Das Übersetzungsplugin wurde von Reinhard Jung erstellt und sollte demnächst auch auf RIAForge veröffentlicht werden.

Der pluginMan kann ebenfalls von RIAForge heruntergeladen werden.

UPDATE: Das Languages Plugin ist nun auf RIAForge verfügbar. Es kann hier heruntergeladen werden.

Mehr lesen Kategorien: ColdFusion

dump in cfscript

0

Welcher ColdFusion Programmierer kennt das nicht: Man möchte innerhalb eines script-Blocks eine Variable ausgeben. Leider hat man dort allerdings die cfdump Funktion nicht zur Verfügung und erstellt normalerweise eine dummy Funktion.

&lt;cffunction name="dump"&gt;
&lt;cfargument name="myVar" /&gt;
&lt;cfdump var="#myVar#" /&gt;
&lt;/cffunction&gt;

Soeben bin ich über einen Hilfreichen Tipp auf Anuj Gakhar’s Blog gestolpert:

&lt;cfscript&gt;
adminApi = createObject("component","cfide.adminapi.security");
myVar = "hello world";
adminApi.dump(myVar);
&lt;/cfscript&gt;

UPDATE: Noch ein kleiner Nachtrag. Ab ColdFusion 9 kann des Programmierers Freund und Helfer auch direkt in cfscript verwendet werden. Der Befehl heisst writeDump

myVar = "hello world";
writeDump(myVar);
Mehr lesen Kategorien: ColdFusion

SHA1 und ColdFusion 6.1

0

Der SHA1 Algorithmus kann bei älteren ColdFusion Versionen nicht direkt verwendet werden um einen Hash String zu erzeugen. Deshalb verwendete ich bis anhin die SHA1 Implementierung von Rob Brooks-Bilson von CFlib.org.

Diese Implementierung basiert auf dem Custom Tag Code von Tim McCarthy. Heute bin ich über einen bemerkenswerten Fehler in dieser Implementierung gestolpert.

Lustigerweise wird bei einer Message Länge von 55 Zeichen ein falscher Hash String generiert.

Der folgende Code

&lt;cfset str = "ABCDE1234567890abcdefghijklmnopqrstuvwxyz0987654321WXYZ" /&gt;
&lt;cfoutput&gt;#sha1(str)#&lt;/cfoutput&gt;

erzeugt diese Ausgabe:

9C10E5A45AC5BEF4D0810E308CAE4514256A8521

Nutzt man unter ColdFusion 9 die hash - Funktion, so erscheint ein anderer Hashwert. Da erzeugt der Code

&lt;cfset str = "ABCDE1234567890abcdefghijklmnopqrstuvwxyz0987654321WXYZ" /&gt;
&lt;cfoutput&gt;#hash(str,"SHA")#&lt;/cfoutput&gt;

auf magische (aber korrekte) Art und Weise die folgende Ausgabe:

132D865A5630AAEE0BCFAA039B60A446DB675404

Unglücklicherweise kann bei zu alten ColdFusion Versionen nicht auf die hash - Funktion zurückgegriffen werden. Der optionale Parameter für den Algorithmus wurde erst in der Version 7 hinzugefügt. Für ColdFusion ab Version 6 schafft zumindest Railo abhilfe.

Von dort kann die korrekt arbeitende Java Klasse railo.runtime.crypt.SHA1 extrahiert und als Hotfix eingebunden werden. Innerhalb von ColdFusion kann dann ganz einfach auf die Java Klasse zurückgegriffen werden:

&lt;cfset str = "ABCDE1234567890abcdefghijklmnopqrstuvwxyz0987654321WXYZ" /&gt;
&lt;cfset jSHA1 = createObject("java","railo.runtime.crypt.SHA1") /&gt;
&lt;cfset jSHA1.update(javaCast("string",str)) /&gt;
&lt;cfset jSHA1.finalize() /&gt;
&lt;cfoutput&gt;#uCase(jSHA1.toString())#&lt;/cfoutput&gt;

This Is That?

1

Heute hatte ich eine nette Diskussion mit dem Herrn der Landstrasse. Es ging um die weitverbreitete und vielfach genutzte init - Methode von Komponenten. Genauer gesagt, um ihren Rückgabewert “this”.

Schauen wir uns einmal eine flugzeug.cfc mit einer init - Methode an:

&lt;cfcomponent displayname="Flugzeug"&gt;

&lt;cffunction name="init" access="public" output="false" returntype="flugzeug" hint="Konstruktor des Flugzeugs"&gt;

...

&lt;cfreturn this /&gt;
&lt;/cffunction&gt;

&lt;/cfcomponent&gt;

Das Flugzeug wird nun als Objekt angelegt und die init - Methode initialisiert die Umgebung die das Flugzeug für seine Arbeit benötigt:

&lt;cfset local.flugzeug = createObject("component","flugzeug").init() /&gt;

Soweit so klar - aber was macht nun genau dieses “this”?

Eigentlich ganz einfach und wenn man die Header - Informationen der Funktion ansieht auch offensichtlich: Es liefert mir das Flugzeug.

In der Praxis bedeutet dies, dass ich eben anstatt

&lt;cfset local.flugzeug = createObject("component","flugzeug") /&gt;
&lt;cfset local.flugzeug.init() /&gt;

die oben erwähnte Schreibweise anwenden kann.

Spinnt man diesen Gedanken weiter sind aus Java bekannte, gefühlte 4’000’000 Zeichen lange Einzeiler möglich. Wir schauen uns dazu erst die mit Methoden angehäufte Komponente an:

&lt;cfcomponent displayname="Flugzeug"&gt;

&lt;cffunction name="init" access="public" output="false" returntype="flugzeug" hint="Konstruktor des Flugzeugs"&gt;

...

&lt;cfreturn this /&gt;
&lt;/cffunction&gt;


&lt;cffunction name="closeDoors" access="public" output="false" returntype="flugzeug" hint="Schliesst alle Tueren"&gt;

...

&lt;cfreturn this /&gt;
&lt;/cffunction&gt;


&lt;cffunction name="startEngine" access="public" output="false" returntype="flugzeug" hint="Startet den Motor"&gt;

...

&lt;cfreturn this /&gt;
&lt;/cffunction&gt;


&lt;cffunction name="doTakeOff" access="public" output="false" returntype="flugzeug" hint="Startet das Flugzeug"&gt;

...

&lt;cfreturn this /&gt;
&lt;/cffunction&gt;

&lt;/cfcomponent&gt;

Es gibt nun zwei Möglichkeiten um das Flugzeug zu starten.

Die meisten ColdFusion Programmierer würden sich für das gute alte Handwerk entscheiden:

&lt;cfset local.flugzeug = createObject("component","flugzeug") /&gt;
&lt;cfset local.flugzeug.init() /&gt;
&lt;cfset local.flugzeug.closeDoors() /&gt;
&lt;cfset local.flugzeug.startEngine() /&gt;
&lt;cfset local.flugzeug.doTakeOff() /&gt;

Da die einzelnen Methoden allerdings jeweils das Objekt selbst zurückliefern, kann man sich hier jede Menge Schreibarbeit ersparen:

&lt;cfset local.flugzeug = createObject("component","flugzeug").init().closeDoors().startEngine().doTakeOff() /&gt;

Natürlich macht dieses Vorgehen nicht immer Sinn - es soll lediglich die Funktionsweise des Objektrückgabewertes “this” verdeutlichen.

Alles in Allem bleibt nur noch zu sagen:
Nehmt euch in acht liebe Java Programmierer, auch wir können die Zeilenlänge ins unermessliche treiben!

Mehr lesen Kategorien: ColdFusion