The Idea
Mixins will give us some multiple inheritance features that can’t always be solved elegantly using traditional inheritance.
A useful example could be SEO properties that apply to both versioned and non-versioned objects, but not all objects of those types (i.e. a content type doesn’t always represent a “page”).
The properties and methods of a component can be “mixed in” to an existing component to provide functionality just as if they were originally defined in the component, and the webskins of that mixin could also be made available to the content type that is inheriting it just as if the webskin was present in that content types webskin path.
Implementation
To do this we would introduce a new packages/mixins
folder where mixin conponents are found, and the usual cascading lookup for core, plugins and projects would apply. To implement the mixin in a component you would call a mixin()
method after your existing property statements.
The mixin()
method could also have optional arguments to allow overriding of formtools metadata attributes such as;
- baseSeq - an offset which is added to the ftSeq values in the mixin component
- ftWizardStep - an override for the ftWizardStep in the mixin component
- ftFieldset - an override for the ftFieldset in the mixin component
The performance overhead for content types using mixins should be close to zero as the component metadata can be cached the same way we already do for normal content types, and the mixin itself is essentially done by appending to an array.
Currently I have a working prototype that handles mixin properties, with functions and webskins yet to be implemented.
Example Code
The example below illustrates a mixin called mixinSEO.cfc
which is implemented in a content type called myPage.cfc
.
projects/demo/packages/types/myPage.cfc
<cfcomponent extends="farcry.core.packages.types.types">
<cfproperty name="title" type="string" required="false"
ftSeq="1" ftWizardStep="" ftFieldset="Page" ftLabel="Title">
<cfproperty name="teaser" type="string" required="false"
ftSeq="2" ftWizardStep="" ftFieldset="Page" ftLabel="Teaser">
<cfproperty name="body" type="string" required="false"
ftSeq="3" ftWizardStep="" ftFieldset="Page" ftLabel="Body">
<cfset mixin(typename="mixinSEO", baseSeq=10, ftFieldset="Search Engine Optimisation")>
<cffunction name="someMethod">
</cffunction>
</cfcomponent>
projects/demo/packages/mixins/mixinSEO.cfc
<cfcomponent>
<cfproperty name="seoTitle" type="string" required="false"
ftSeq="1" ftWizardStep="" ftFieldset="SEO" ftLabel="SEO Title">
<cfproperty name="seoDescription" type="string" required="false"
ftSeq="2" ftWizardStep="" ftFieldset="SEO" ftLabel="SEO Description">
<cfproperty name="seoKeywords" type="string" required="false"
ftSeq="3" ftWizardStep="" ftFieldset="SEO" ftLabel="SEO Keywords">
</cfcomponent>
projects/demo/packages/webskins/mixinSEO/displaySEO.cfm
<cfoutput>
<meta name="description" content="#encodeForHTMLAttribute(stObj.seoDescription)#">
</cfoutput>