Contents |
Code Generation Tools
Transfer now ships with extensible utilities to generate code for you, to help decrease your development time even further.
We will look at both the code generation functionality that is included with Transfer and the accompanying templates, and also how to write your own templates, and also your own Generators.
The Code Generation tools revolve around generating code based on Transfer configuration meta data, but could possibly be used as a template engine to generate code based on almost any meta data.
Accessing the GenerationManager
All code generation is performed through the GenerationManager, which we can access from the TransferFactory's getGenerationManager() method, like so:
<cfscript>
transferFactory = createObject("component", "transfer.TransferFactory").init("datasource.xml", "transfer.xml");
generationManager = transferFactory.getGenerationManager();
</cfscript>
Decorator Generator
Transfer comes bundled with a Generator to generate your Decorators for you.
The generator will inspect your configuration XML file, and for each <object> definition that has a decorator, it will generate the Decorator CFC for you, depending on which template you select.
For example, to use the basic decorator template, which comes with Transfer:
<cfscript>
generationManager = transferFactory.getGenerationManager();
//get the decorator generator
generator = generationManager.createDecoratorGenerator();
//set the template to use
generator.setTemplate("Basic.cfc");
//run the generator.
generator.run();
</cfscript>
This will create each and every Decorator that has been specified in your configuration XML file.
It should be noted that code generator will use protected blocks within generated code (strings to mark out generated areas), and only ever update those areas. This gives you the choice of either editing around the protected areas (which some will argue is a bad idea), or alternatively, extending the generated code, and adding additional functionality that way. Which way you choose to extend the generated code base is entirely up to you, and the project you are working on.
This also means that if you ever add a new protected block to your code generation template, you can simply add the protected block marker strings to the CFC that has been previously generated, and the code that is meant to reside there will be generated.
Basic.cfc Template
This is a template that ships with Transfer, that simply generates a Decorator stub, with no additional functionality in it.
Remoting.cfc Template
This is a template that ships with Transfer that generates the required <cfproperty> tags, and <cfcomponent> attributes to work with Conduit based Flex integration. Read more in Integrating Transfer and Flex.
Writing Your own Decorator Templates
It is also possible to write your own Decorator Templates, to be run by the Decorator Generator.
A Decorator template is simply a normal CFC, except in the code, where you want dynamic variables,
- # becomes $$
- < becomes {{
- > becomes }}
For example, a simple Decorator Template may look like:
<cfcomponent output="false" hint="Decorator for $$state.object.getClassName()$$" extends="transfer.com.TransferDecorator">
<--- a displayed comment --->
{{--- this serves no purpose other than to demonstrate the syntax ---}}
{{cfset local.x = 3 * 4 }}
</cfcomponent>
We won't worry about what the state and local objects are, but the hint attribute of <cfcomponent> has the class name from the meta data dynamically generated, because of the $$ around it.
We can also see that while running the code generation, the value of local.x will be set to 12 (i.e. 3 * 4), although it is never actually used anywhere.
To run our own template, we simple set the setTemplate method on the Decorator Generator to the path to our own Template, like so:
<cfscript>
generationManager = transferFactory.getGenerationManager();
//get the decorator generator
generator = generationManager.createDecoratorGenerator();
//set the template to use
generator.setTemplate("/path/to/my/Template.cfc");
//run the generator.
generator.run();
</cfscript>
Template Custom Tags
When writing our own Templates, there are several custom tags that are automatically included for use.
gen:block
This custom tag marks a protected block of code within the template.
Syntax
{{gen:block
name="The unique name of this protected block in this template"
}}
{{/gen:block}}
Attributes
| Attribute | Req/Opt | Default | Description |
|---|---|---|---|
| name | Required | - | This gives a name to the protected code block, so it can be found when re-running the code generation tool. |
For example:
{{gen:block name="getPrimaryKey"}}
<cffunction name="getPrimaryKey()" access="public">
<cfreturn get$$local.object.getPrimaryKey().getName()$$() />
</cffunction>
{{/gen:block}}
Would give your getPrimaryKey function, a protected block named 'getPrimaryKey', if you ever wanted to update it.
gen:compact
This custom tag strips empty lines out between the start and end of the tag, which can occur with ColdFusion tag processing.
Syntax
{{gen:compact}}
{{/gen:compact}}
Attributes None.
For example:
{{gen:compact}}
<cfloop from="1" to="10" index="i">
<cfset var var$$i$$ = $$i$$ />
</cfloop>
{{/gen:compact}}
Would display the <cfset> statement, with no empty line breaks in between.
Template State Scope
The state scope is a scope that is specific to the Template, and contains the arguments that the Generator passes into the Template.
In the case of the of the Decorator Generator, you have access to the following items:
| Name | Description |
|---|---|
| object | The transfer.com.object.Object meta data that is for the Decorator that we are generating. |
Template Local Scope
The local scope, is simply a local scope for the template to store your own variables when writing your own templates.
For example:
{{cfset local.iterator = state.object.getPropertyIterator() /}}
{{cfloop condition="$$local.iterator.hasNext()$$"}}
{{cfset local.property = local.iterator.next() /}}
<cfproperty name="$$local.property.getName()$$" type="$$local.property.getType()$$"{{cfif local.property.getIsNullable()}} nullvalue="$$local.property.getNullValue()$$"{{/cfif}}>
{{/cfloop}}
Loops around the properties of the object, and writes <cfproperty> values for each property.
Writing Your Own Generators
It is also possible to write your own Generators, leverage the templating syntax already provided for you by Transfer, and generate whatever you want.
To write your own Generator, you need to implement a CFC that extends transfer.com.codegen.generator.AbstractBaseGenerator, and implements the run() method.
To write a file using the Templating System, you want to use the writeTemplate() method, to write the actual file. It should be noted that whatever arguments are passed into the writeTemplate() function, are passed into the state scope that is available to Template, so you can pass in as many argument parameters as you like.
It is worth looking at the AbstractBaseGenerator to review what data is available to the Generator, and also looking at the source code for the Decorator Generator.
To initialise your custom Generator, you will need to run:
<cfscript>
generationManager = transferFactory.getGenerationManager();
//get the decorator generator
generator = generationManager.create("com.my.cfc.CustomGenerator");
</cfscript>
This create statement will initialise the Generator with the appropriate dependencies.
It is interesting to note that GenerationManager.createDecoratorGenerator() is simple a shortcut to calling:
<cfreturn create("transfer.com.codegen.generator.decorator.Generator") />
Categories:
Wiki Menu
User Login