Macros to assemble arbitrary content items inside other templates

I’ve created the following macros to enable me to include assembled content from arbitrary content items within the templates of other items.

## macro to create an assembly item from scratch.
## Sam Rushing, July 31, 2009 
#macro(createAssemblyItem $asmItem $contentid $revision $templateName $params)##
#set( $asmItem = $sys.asm.createAssemblyItem() )##
$asmItem.setTemplate($sys.asm.findTemplateByName( $templateName ))##
$asmItem.setJobId( $sys.assemblyItem.getJobId() )##
$asmItem.setVariables( $sys.assemblyItem.getVariables() )##
#set( $tempparams = $rx.asmhelper.combine($sys.params,$params) )##
$asmItem.setParameters( $rx.asmhelper.combine($tempparams,"sys_contentid=${contentid}&sys_revision=${revision}") )##
$asmItem.normalize()##
#end

## macro to assemble a manually created assembly item and return the results
## Sam Rushing, July 31, 2009 
#macro(assembleItem $assemblyResult $assemblyItem)##
#set( $assemblyResult = $sys.asm.assemble( [$assemblyItem] ).get(0).toResultString() )##
#end

## macro to autonomously assemble an item from its content ID, revision, template name and additional parameters
## Sam Rushing, July 31, 2009 
#macro(assemble $contentid $revision $templateName $params)##
#createAssemblyItem( $asmItem $contentid $revision $templateName $params )##
#assembleItem( $result $asmItem )##
$result##
#end

There are probably better was of doing this, but as an example, I’ve used these macros to build navigation panels for some subcategory preview templates (where subcategories are associated to categories by adding them to a slot in the parent category – yes, I know this is a bit strange, but we needed to have an easy way to force an order on the subcategories.):

#set( $contentid = $sys.item.getProperty('rx.sys_contentid').string )
#set( $category = $rx.db.get( '', "select s.contentid, s.editrevision from psx_objectrelationship r, contentstatus s where r.owner_id = s.contentid and ((s.editrevision = -1 and r.owner_revision = s.currentrevision) or (s.editrevision <> -1 and r.owner_revision = s.editrevision)) and r.dependent_id = $contentid").get(0) )
<div class="page-content">
    <div class="navigation-panel">
#assemble( $category.get('CONTENTID') $category.get('EDITREVISION') 'Category_Nav_Preview' "highlight=$contentid" )
    </div>
    <div class="content-body">
        ...
    </div>
</div>

I really appreciate your help and I am starting to see how this could work, however maybe you can help me pick apart this problem.

I have a landing page that has a slot called “erauFacultyFullPage”, which holds one item, the full generic page that has a slot for a faculty spotlight. This faculty spotlight slot is what I want to get the items from, so doing a simple initslot(‘erauFacultyFullPage’) on the landing page and displaying the results reveals the page assembly information with the slot.

Do I need to assemble the page if I already have all of the assembly information? I was thinking I could do something like this:


#initslot('erauFacultyFullPage')##
#foreach($result in $sys.currentslot.relresults)##
$user.psoSlotTools.getSlotContents($result,'erauBottomIndex',"template=erauSnContactQuote")
#end

But that is not working. I tried to use your code to assemble the item from the content id but that did not produce any results. Can you see what I am doing wrong?

I combined the three macros into one

macro to create an assembly item from scratch.

#macro(assemble $asmitem $contentid $revision $templateName $params)##
#set( $asmitem = $sys.asm.createAssemblyItem() )##
$asmitem.setTemplate($sys.asm.findTemplateByName( $templateName ))##
$asmitem.setJobId( $sys.assemblyItem.getJobId() )##
$asmitem.setVariables( $sys.assemblyItem.getVariables() )##
#set( $tempparams = $rx.asmhelper.combine($sys.params,$params) )##
$asmitem.setParameters( $rx.asmhelper.combine($tempparams,“sys_contentid=${contentid}&sys_revision=${revision}”) )##
$asmitem.normalize()##
#set( $asmresult = $sys.asm.assemble($asmitem).get(0).toResultString() )##
#end

and then called the macro as in
#assemble($asmitem $jobcontentid “-1” “wwwSnippetLinkAndIcon” “”)
#set($joblink = $jobcontentid + “:” + $asmresult)

and returns

6059:$asmresult

6087:$asmresult

Any idea what causes the problem? BTW: how do I get and pass in the revision to retrieve the latest? right now I passed in -1

Thanks, LH

I’ve been fiddling with this a little more. I’ve come up with a few changes to the base macro from earlier:


## macro to create an assembly item from scratch.
## Sam Rushing, March 11, 20011 
#macro(createAssemblyItem $asmItem $contentid $revision $templateName $params)
#set( $asmItem = $sys.assemblyItem.clone() )
$asmItem.setTemplate( null )##
$asmItem.setNode( null )##
#set( $tempparams = $rx.asmhelper.combine($sys.params,$params) )
#set( $tempparams = $rx.asmhelper.combine($tempparams,"sys_contentid=${contentid}&sys_revision=${revision}&sys_template=${templateName}") )
$asmItem.setParameters( $tempparams )##
$asmItem.normalize()##
#end

## macro to assemble a manually created assembly item and return the results. Returns an empty string if there's an error.
## Sam Rushing, March 11, 20011 
#macro(assembleItem $assemblyResult $assemblyItem)##
#set( $assemblyResult = "$!{rx.doc.extractBody($sys.asm.assemble( [$assemblyItem] ).get(0))}" )##
#end

So, the main change here is that this version does not break the clonedParent chain, so you can refer back to the main content item from the assembly of the new item you created with the macro.

Setting the node and template to null in the macro above allow the call to normalize to load the node and set the template based off the parameter string. (satisfying the DRY programming principle)

In reply to Lan,

You should really reuse code instead of re-inventing stuff… Unless you have a very good reason, your assemble macro should be something like this:


## macro to create an assembly item from scratch and put the results into a variable.
#macro(assembleIntoVar $targetVar $contentid $revision $templateName $params)
#set( $targetVar = "#assemble($contentid $revision $templateName $params)" )
#end

See, the concept you seem to have missed is that $asmItem isn’t a variable local to the macro, it’s a return value. The macro you defined set the global $asmitem variable, not because you set it inside the macro, but because you passed in the reference to the global variable in the macro call. I’m not sure why you never got results, but I bet there’d be a clue on your logs… It’s been a while since you posted, so I bet you’ve found a work-around already.

In all three of the macros in this post, I used the 1st parameter as a return value. One of the basic concepts of macros is that all parameters of the macro are both readable and writable. Macros are not functions, procedures, or methods. The parameters aren’t even actual variables, but placeholders to the variables or values that were passed in. If you’re used to programming in a high-level language, the macro concept can be very confusing.

I’ve merged the functionality of these macros into AtcToolkit as $user.asmTools.