UNIT 06 - Content Relationships
Objectives
By the end of this unit you will have learnt how to relate content types to one another, using one-to-many and many-to-many relationships. You will be able to create user interfaces to allow editors to select and relate objects from libraries.
Array Properties
An array property can contain a series of object references to other objects in the COAPI; a many-to-many relationship. When it's presented to the system view or webskin it's represented as an actual array property, where each index contains the objectid (or primary key) of the related object. This objectid can then be used to reference the related object as needed. In addition, the order (or sequence) of the relationship is preserved so that programmers can rely on the order to be exactly as the user nominated.
Array properties in terms of how they are defined in a content type really don't differ all that much to normal properties. You add a <cfproperty> and simply define type="array" and a list of content types that you would like to allow to be associated using ftJoin, for example ftJoin="superPower". However, what happens behind the scenes is much more involved.
<cfcomponent ..> ... <cfproperty name="aPowers" type="array" hint="Array of superhuman powers." ftSeq="12" ftFieldset="Related Content" ftWizardStep="Relationships" ftLabel="Powers" ftType="array" ftJoin="superPower" /> ... </cfcomponent>
Array Properties Must Start With "a"
Array properties must be prefixed with the letter "a". If you don't do that then the deployment window will not be able to correctly detect that you have deployed the array property.
If you open up the database model after you deploy an array property, you'll notice that the property (for example, aPowers) is not represented by a column in the table. Array data is essentially an index of references to other objects and is defined by its own linked table (for example, superHero_aPowers). The array table includes the parent object, the referenced objectid, the sequence multiple entries should be represented in, and the typename of the referenced object. Importantly, the data model in the database itself does not need to be understood to work with arrays - the framework handles recording and retrieving this information.
Extended Arrays
Array properties can themselves be extended to include additional attributes - but lets keep it simple for now.
ftJoin is a critical piece of metadata as it designates exactly what content types are allowed to be related to this specific property. Interestingly, FarCry Framework is quite happy to have multiple content types referenced, even though the content types themselves may have very different sets of properties. The default UI controls for libraries are designed to allow users to switch between nominated content types if multiple types have been referenced.
<cfproperty name="aMedia" type="array" hint="Local media library." required="no" default="" ftSeq="13" ftFieldset="Relationships" ftLabel="Associated Media" ftType="array" ftJoin="dmImage,dmFile,dmFlash" />
By default the library UI control for an array property will list all content objects of the nominated type, ordered by datetimelastupdated.
Library Options
It won't surprise you that the options for the library are extensive and include the ability to restrict what content objects are available, the order they are displayed, how they are displayed and so on. Review the formtool metadata dictionary entry on Libraries for more details.
Walkthrough: Super Powers
We're going to add an array property [aPowers] to join our hero to the powers they possess.
- Open the ./packages/types/superHero.cfc component for editing.
- Add the following property
<cfproperty ftSeq="12" ftFieldset="Related Content" ftWizardStep="Relationships" name="aPowers" type="array" ftLabel="Powers" ftJoin="superPower" hint="Array of superhuman powers." />
- Go to the webtop COAPI admin area and deploy your new property
- If you have a tool for browsing the database schema, now would be a good time to take a look at the underlying array table
- many to many relationship (bridging table)
- ParentID, Data, Seq, Typename
- Reload the COAPI Metadata
- Go to the Super Hero administration screen, and associate super powers from the library picker that should now be available in the edit handler.
Library Selected Webskin
By default the library will only show a content object's label, and if that's blank the objectid. However, like many aspects of the framework, this behaviour can be modified to suit your specific application. FarCry Framework has a special webskin (or view) for rendering the objects selected for the library: ./webskin/typename/librarySelected.cfm (where typename is represented by the actual typename you are trying to modify).
Walkthrough: Library Selected
Your super powers only shows the label for your content object. Lets make that look prettier.
- Create a new webskin template ./webskin/superPower/librarySelected.cfm
- Copy the following code into the webskin:
<cfsetting enablecfoutputonly="true" /> <!--- @@displayname: Power (Library) ---> <cfoutput> <div> <img src="#application.url.webroot##stobj.imgPower#" alt="#stobj.title#" title="#stobj.title#" /> #stobj.title#<br /> #stobj.description# </div> </cfoutput> <cfsetting enablecfoutputonly="false" />
- Reload the COAPI Metadata to register the newly added webskin.
- Go back to the Super Hero admin and try adding super powers. Make sure your librarySelected webskin is working as expected.
UUID Property
A UUID property is a single object reference or one-to-many relationship. It behaves in very much the same way as an array property in terms of UI and the library options that are available. The object reference is stored in a simple string field in the database.
<cfproperty name="sidekickid" type="uuid" hint="Super hero sidekick." ftSeq="11" ftFieldset="Related Content" ftWizardStep="Relationships" ftLabel="Sidekick" ftType="uuid" ftJoin="superHero" />
Walkthrough: Side Kick (there can be only one)
Let's create an option to select another hero in the system as a sidekick.
- Open the ./packages/types/superHero.cfc component for editing.
- Add a UUID property for sidekickid
<cfproperty name="sidekickid" type="uuid" hint="Super hero sidekick." ftSeq="11" ftFieldset="Related Content" ftWizardStep="Relationships" ftLabel="Sidekick" ftType="uuid" ftJoin="superHero" />
- Go to the webtop COAPI admin area. You should see a single conflict for the Super Hero component.
- Deploy the sidekickid UUID property.
- Go to the Super Hero administration screen, and associate a side-kick from the library picker that should now be available in the edit handler.
Lab: Super Group
Create your own "super group" content type, complete with an array of super hero objects.
- Create a new component; ./packages/types/superGroup.cfc
- title (string, required)
- description (longchar, rich text area)
- headquarters (string)
- imgHeadquarters (image; 200x200 dimensions, fit inside)
- aSuperHeroes (joining to superHero)
- Deploy the new content type under the COAPI area
- Use the scaffold utility to create an admin area and default webskins
- Go to the administration area and add "Super Groups" containing your favourite Super Heroes
Bonus Points
If you are feeling super-keen, add a librarySelected webskin for your Super Hero content type.