Common Bean Objects

The following table contains information about Mura's most commonly used bean objects.

Bean Load By Description
configBean n/a Includes instance-wide configuration data, such as data collected in the settings.ini.cfm file. 
site siteid Includes site configuration data collected via the Site Settings section in the administration area, as well as other useful site-specific information.
content contentid,
contenthistid,
filename,
remoteid,
title,
urltitle
Includes data about a Mura content item, such as the title, summary, body, etc. In addition, there are several content-specific helper methods included. For example, you could get an iterator of any children of the content item, what specific categories the content item has been assigned to, etc.
user userid,
username,
remoteid
Includes user-specific data, and includes a number of helper methods. For example, you can obtain an iterator of the groups the user belongs to, etc.
group groupid,
groupname,
remoteid
Includes group-specific data, and includes a number of helper methods. For example, you can obtain an iterator of the users who belong to the group, etc.
comment commentid,
remoteid
Includes comment-specific data. In addition, there are some comment-specific helper methods included such as whether the comment is approved, deleted, etc.
category categoryid,
name,
remoteid,
filename,
urltitle
Includes category-specific data. This bean contains information about a category itself, and does not describe any relationships to content items themselves.
feed feedid,
name,
remoteid
Allows developers to programmatically query Mura for other beans/objects (such as content items, users, and/or custom objects), based on desired filters or search criteria.

Inspecting Available Attributes

For each of the above beans/objects, using CFML's <cfdump> tag, you can easily inspect the available attributes and their values using the code examples below.

<!--- Loading a bean/object --->
<cfset someBean = m.getBean('{someBean}').loadBy({someAttribute}={someAttributeValue})>

<!--- Assumes you have a properly loaded bean --->
<cfdump var="#someBean.getAllValues()#">

Config Bean

The configBean object includes instance-wide configuration data, primarily the data collected in the settings.ini.cfm file.

See the Mura Scope's globalConfig subscope to access the same information.

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the configBean. Use whichever syntax feels best to you.

Loading the Bean

The configBean is the only bean/object that doesn't require a call to loadBy to get a populated bean, since it's loaded when the application is initialized.

<cfset configBean = m.getBean('configBean')>

Once you have a variable to to reference the desired bean/object, you can use the example Getters and Setters below.

Getters

configBean.get('attributeName')
configBean.get{AttributeName}()
configBean.getValue('attributeName')

Setters

configBean.set('attributeName', 'someValue')
configBean.set{AttributeName}('someValue')
configBean.setValue('attributeName', 'someValue')

Note: Setting any values of the configBean are only temporary, and last for the duration of the request. In other words, calling the save method on configBean will not save any values.

Usage

Use the configBean bean/object to access global configuration attributes.

Attributes

The table below lists available attributes. For the vast majority of the attributes listed below, you may reference the settings.ini.cfm section for details.

Attribute
admindir
admindomain
adminemail
adminssl
allowautoupdates
allowedindexfiles
allowlocalfiles
allowquerycaching
allowsimplehtmlforms
allowunicodeinfilenames
applydbupdates
appreloadkey
assetdir
assetpath
autodiscoverplugins
autoresetpasswords
bcryptpasswords
broadcastappreloads
broadcastcachepurges
broadcastwithproxy
cffpconfigfilename
cfstaticjavaloaderscope
clearsessionhistory
clusteriplist
compiler
confirmsaveasdraft
contact
context
cookiedomain
cookiepath
createrequireddirectories
customurlvardelimiters
dashboard
dashboardcomments
datacollection
datasource
dbcasesensitive
dbpassword
dbschema
dbtablespace
dbtype
dbusername
debuggingenabled
defaultflatviewrange
defaultflatviewtable
duplicatetransients
emailbroadcaster
enablemuratag
encryptionkey
encryptpasswords
extensionmanager
filedelim
filedir
filestore
filestoreaccessinfo
filestoreendpoint
fmallowedextensions
fmpublicallowedextensions
forceadminssl
hashurls
hasrazuna
hstsmaxage
imageinterpolation
imagequality
indexfile
indexfileinurls
javaenabled
loadcontentby
locale
lockablenodes
logevents
loginstrikes
mailserverip
mailserverpassword
mailserverpopport
mailserversmtpport
mailserverssl
mailservertls
mailserverusername
mailserverusernameemail
managelinks
mapdir
maxarchivedversions
maxsourceimagewidth
mfaenabled
mfaperdeviceenabled
mfasendauthcode
mode
mysqlengine
notifywithversionlink
plugindir
pluginspath
postbundles
productionassetdir
productionassetpath
productiondatasource
productionfiledir
productionpushmode
productionwebroot
proxypassword
proxyport
proxyserver
proxyuser
purgecomments
purgedrafts
readonlydatasource
readonlydbpassword
readonlydbusername
requirementspath
saveemptyextendedvalues
scriptprotect
scriptprotectexceptions
securecookies
sendfrommailserverusername
serverport
sessioncookiesexpires
sessionhistory
sessiontimeout
sharableremotesessions
showadminloginhelp
sitedir
siteidinurls
skipcleanfilecache
sortpermission
strictfactory
strongpasswordregex
tempdir
title
tooltips
urltitledelim
usedefaultsmtpserver
version
webroot
webrootmap
advancedcaching
alwaysuselocalrenderer
autoupdatemode
clientmanagement
clientstorage
customtagpaths
defaultfilemode
donottrackagents
editablecomments
errortemplate
fmshowapplicationroot
fmshowsitefiles
haslockablenodes
javasettingsloadcoldfusionclasspath
javasettingsreloadonchage
javasettingswatchextensions
javasettingswatchinterval
maxportalitems
mfa
mfaperdevice
ormautomanagesession
ormcfclocation
ormdatasource
ormdbcreate
ormenabled
ormeventhandling
ormflushatrequestend
ormlogsql
ormsavemapping
ormskipcfcwitherror
ormusedbformapping
ping
recaptchalanguage
recaptchasecret
recaptchasitekey
rendermuraalerts
requesttimeout
sameformfieldsasarray
strongpasswords
testbox
usefilemode
windowdocumentdomain

 

Site Bean

The site bean/object includes site configuration data collected via the Site Settings section in the administration area, as well as other site-specific information.

See the Mura Scope's siteConfig subscope to access the same information when working with the site being used in the current request.

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the site bean/object. Use whichever syntax feels best to you.

Loading the Bean

You should load a site bean/object by a SiteID. You can use any SiteID you wish, or simply use the session.siteid when you wish to work with the site associated with the existing request.

<cfset siteBean = m.getBean('site').loadBy(siteid=session.siteid)>

Once you have a variable to reference the desired bean/object, you can use the example Getters and Setters below.

Getters

siteBean.get('attributeName')
siteBean.get{AttributeName}()
siteBean.getValue('attributeName')

Setters

siteBean.set('attributeName', 'someValue')
siteBean.set{AttributeName}('someValue')
siteBean.setValue('attributeName', 'someValue')

Usage

Use the site bean/object to access and/or manipulate "site" configuration attributes.

Attributes

The table below lists available attributes.

Attribute
accountactivationscript
addobjects
admanager
advertiseruserpoolid
baseid
cache
cachecapacity
cachefactories
cachefreememorythreshold
categorypoolid
columncount
columnnames
commentapprovaldefault
contact
contactaddress
contactcity
contactemail
contactname
contactphone
contactstate
contactzip
contentapprovalscript
contentcanceledscript
contentpendingscript
contentpoolid
contentrejectionscript
contentrenderer
contenttypefilepathlookup
contenttypeloopuparray
customtaggroups
datacollection
deploy
displayobjectfilepathlookup
displayobjectlookup
displayobjectloopuparray
displaypoolid
domain
domainalias
editprofileurl
emailbroadcaster
emailbroadcasterlimit
enablelockdown
enforcechangesets
enforceprimarydomain
errors
exportlocation
extendautocomplete
extenddata
extenddatatable
extendsetid
extranet
extranetpublicreg
extranetpublicregnotify
extranetssl
feedmanager
filepoolid
frommuracache
googleapikey
haschangesets
hascomments
haslockablenodes
hassharedfilepool
instanceid
isnew
isremote
javalocale
jsdatekey
jsdatekeyobjinc
jsonapi
largeimageheight
largeimagewidth
lastdeployment
locking
loginurl
mailinglistconfirmscript
mailserverip
mailserverpassword
mailserverpopport
mailserversmtpport
mailserverssl
mailservertls
mailserverusername
mailserverusernameemail
mediumimageheight
mediumimagewidth
nextn
orderno
pagelimit
placeholderimgext
placeholderimgid
primarycolumn
privateuserpoolid
publicsubmission
publicsubmissionapprovalscript
publicuserpoolid
rbfactory
recaptchalanguage
recaptchasecret
recaptchasitekey
reminderscript
remotecontext
remoteport
resourcedomain
resourcessl
sendauthcodescript
sendloginscript
showdashboard
site
siteid
sitelocale
smallimageheight
smallimagewidth
sourceiterator
subtype
tagline
theme
themelookup
themerenderer
type
usedefaultsmtpserver
usessl
viewdepth

Content Bean

The content bean/object includes data about a Mura content item, such as the title, summary, body, etc. In addition, there are several content-specific helper methods included. For example, you could get an iterator of any children of the content item, what specific categories the content item has been assigned to, etc.

See the Mura Scope's content subscope to access the same information when working with a content item being used in the current request.

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the content bean/object. Use whichever syntax feels best to you.

Loading the Bean

You can load a content bean/object by any of the following attributes:

  • contentid
  • contenthistid
  • filename
  • remoteid
  • title
  • urltitle
<cfset contentBean = m.getBean('content').loadBy(title='Home')>

Once you have a variable to reference the desired bean/object, you can use the example Getters and Setters below.

Getters

contentBean.get('attributeName')
contentBean.get{AttributeName}()
contentBean.getValue('attributeName')

Setters

contentBean.set('attributeName', 'someValue')
contentBean.set{AttributeName}('someValue')
contentBean.setValue('attributeName', 'someValue')

Usage

Use the content bean/object to access and/or manipulate a content item.

Attributes

The table below lists available attributes.

Attribute Description
active Whether the content item is active.
approvalchainoverride Whether to ignore approval chain, if applied.
approvalgroupid The current approval chain GroupID the content item is assigned to.
approvalstatus The approval status of the content item.
approved Whether the content item is approved.
assocfilename The name of the file of the primary associated image/file.
body The main content/body of the content item.
categoryid A comma-delimited list of CategoryIDs associated with the content item.
changesetid The ChangeSetID the specific content item version is associated with, if any.
childtemplate Default template to be applied to children, if any.
contenthistid A unique identifier for the specific version of the content item.
contentid A unique identifier for the content item.
created Date/time the content was originally created.
credits The credits field of the content item. Similar to a byline.
depth A numeric representation of number of levels deep the content item resides in relation to the "Home" page.
display Whether to display the content item.
displayinterval If "display" is set to "Per Schedule", a JSON-encoded string representing the scheduled display interval.
displaystart If "display" is set to "Per Schedule", the date/time to begin displaying the content item.
displaystop If "display" is set to "Per Schedule", the date/time to stop displaying the content item.
expires The content expiration date field of the content item.
featurestart If the content item is featured, the date/time to begin featuring it.
featurestop If the content item is featured, the date/time to stop being featured.
fileext The file extension of the primary associated image/file.
fileid The FileID of the primary associated image/file.
filename The URL to the content item, excluding the domain name.
filesize The file size of the primary associated image/file.
htmltitle The HTML Title field of the content item.
imageheight If the content item is a Folder, and imagesize is "custom" the height in pixels to use for images.
imagesize If the content item is a Folder, the pre-defined size to use for images (e.g., small, medium, large, custom, etc.)
imagewidth If the content item is a Folder, and imagesize is "custom", the width in pixels to use for images.
inheritobjects Whether the content item is inheriting display objects from an ancestor.
isfeature Whether the content item is featured in the section.
ishome Whether the content item is the "Home" page.
islocked Whether the content item is locked, if type is a file.
isnav Whether the content item should be shown in navigational objects generated by Mura.
isnew Whether the content item is new.
lastupdate The date/time the content item was last updated.
lastupdateby The name of the user who last updated the content item.
lastupdatebyid The UserID of the user who last updated the content item.
majorversion The major version number of the content item, if type is a file.
menutitle The Menu Title field of the content item.
metadesc The Meta Description of the content item.
metakeywords The Meta Keywords of the content item.
minorversion The Minor Version of the content item, if the type is a file.
mobileexclude Whether to exclude the content item from navigation objects on mobile devices.
moduleassign If content type is a Form or Component, a comma-delimited list of ModuleIDs of modules to allow the Form/Component to be used in. Essentially, the answer to the "Where would you like to use this Component?" question.
moduleid ModuleID of the content item.
newfile This is the field you set new primary associated files, when creating new content programatically.
nextn If content type is a Folder, the number of records to display on each page.
notes The Notes field of the content item.
objectparams The objectparams of the content item.
orderno The Order Number of the content item, if the parent is using "Manual" sort.
parentid The ContentID of the direct parent of the content item.
path A comma-delimited list of ContentIDs representing the ancestry of the content item.
releasedate The Official Release Date field of the content item.
remoteid A special field for developer's to use. May load the content item by this field. It does not have to be unique. Typically, used to store a unique identifier to associate the content item to an external data store.
remotepubdate A special field for developer's to use when importing or associating content to an external data store.
remotesource A special field for developer's to use when importing or associating content to an external data store. Typically, the name of the external data.
remotesourceurl A special field for developer's to use when importing or associating content to an external data store. Typically, the domain of the external data.
remoteurl A special field for developer's to use when importing or associating content to an external data store. Typically, the full URL to the external content.
restricted Whether the content item is restricted.
restrictgroups A comma-delimited list of GroupIDs to restrict access to.
searchexclude Whether to exclude the content item from Mura's search results.
siteid The SiteID the content item is associated with.
sortby If content type is Folder, which field to sort by.
sortdirection If content type is Folder, which direction to sort by.
status The Status of the content item (e.g., Published, Draft, etc.).
statusid The StatusID of the content item.
subtype Subtype of the content item.
summary The Summary field of the content item.
tags A comma-delimited list of default tags.
target Whether to open in a new browser window.
template The layout template applied directly to the content item. If empty, Mura will traverse up the tree until it locates an applied template, and if none are found or the applied template is not found, will use the default.cfm layout template.
title The main Title field of the content item.
type The type of the content item (e.g., Page, Folder, Calendar, Link, File, etc.)
urltitle The URL Title field of the content item.

Helper Methods

When working with content, the following content bean/object's helper methods may be quite useful.

getCategoriesIterator()

Returns an iterator of categories the content item has been associated with.

<cfset it = contentBean.getCategoriesIterator()>
<!--- Loop over the iterator --->
<cfif it.hasNext()>
  <ul>
    <cfloop condition="it.hasNext()">
      <cfset item = it.next()>
      <li>
        #esapiEncode('html', item.get('name'))#
      </li>
    </cfloop>
  </ul>
<cfelse>
  <!--- Content item has not been categorized --->
</cfif>

getKidsCategoryIterator()

Returns an iterator of categories that children of the content item have been associated with.

<cfset it = contentBean.getKidsCategoryIterator()>
<!--- Loop over the iterator --->
<cfif it.hasNext()>
  <ul>
    <cfloop condition="it.hasNext()">
      <cfset item = it.next()>
      <li>
        #esapiEncode('html', item.get('name'))#
      </li>
    </cfloop>
  </ul>
<cfelse>
  <!--- No child categories exist --->
</cfif>

getRelatedContentIterator()

Returns an iterator of related content items.

<cfset it = contentBean.getRelatedContentIterator()>
<!--- Loop over the iterator --->
<cfif it.hasNext()>
  <ul>
    <cfloop condition="it.hasNext()">
      <cfset item = it.next()>
      <li>
        <a href="#item.get('url')#">
          #esapiEncode('html', item.get('title'))#
        </a>
      </li>
    </cfloop>
  </ul>
<cfelse>
  <!--- No related content items exist --->
</cfif>

You can also optionally pass in a specific Related Content Set name.

<cfset it = contentBean.getRelatedContentIterator(name='Related Videos')>

getCommentsIterator()

Returns an iterator of comments associated with the content item.

<cfset it = contentBean.getCommentsIterator()>
<!--- Loop over the iterator --->
<cfif it.hasNext()>
  <ul>
    <cfloop condition="it.hasNext()">
      <cfset item = it.next()>
      <li>
        <div class="comments-datetime">
          #LSDateFormat(item.get('entered'))# 
          #LSTimeFormat(item.get('entered'))#
        </div>
        <div class="comments-text">
          #esapiEncode('html', item.get('comments'))#
        </div>
        <div class="comments-author">
          #esapiEncode('html', item.get('name'))#
        </div>
      </li>
    </cfloop>
  </ul>
<cfelse>
  <!--- No comments exist --->
</cfif>

User Bean

The user bean/object includes user-specific data, and includes a number of helper methods. For example, you can obtain an iterator of the groups the user belongs to, etc.

Note: The group bean/object is essentially a user bean/object. The primary difference is that the user bean/object contains only user-specific information, and user-specific helper methods. Also, the type attribute will be 1 if a group, and 2 if a user.

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the user bean/object. Use whichever syntax feels best to you.

Loading the Bean

You can load a user bean/object by any of the following attributes:

  • userid
  • username
  • remoteid
<cfset userBean = m.getBean('user').loadBy(username='steve')>

The user bean/object's loadBy method allows for an optional second argument, labeled siteid. This is necessary when working with a user assigned to a different siteid than the site you are currently working with. For example, if you are working on "Site B" and your user was created under the "default" site, then you would have to load the user similar to the example below.

<cfset userBean = m.getBean('user').loadBy(username='steve', siteid='default')>

Once you have a variable to reference the desired bean/object, you can use the example Getters and Setters below.

Getters

userBean.get('attributeName')
userBean.get{AttributeName}()
userBean.getValue('attributeName')

Setters

userBean.set('attributeName', 'someValue')
userBean.set{AttributeName}('someValue')
userBean.setValue('attributeName', 'someValue')

Usage

Use the user bean/object to access and/or manipulate a Mura user.

Attributes

The table below lists available attributes.

Attribute Description
addresses A recordset of the user's addresses.
categoryid A comma-delimited list of CategoryIDs the user has selected as interests.
company The user's company.
created Date/time the user was created.
email The user's email address.
fname The user's first name.
inactive Whether the user/group is inactive.
interests A comma-delimited list of CategoryIDs the user has selected as interests.
isnew Whether the user bean is new.
ispublic Whether the user is a Site Member (1) or System User (0).
jobtitle The user's job title.
lastlogin Date/time the user last logged in.
lastupdate Date/time the user was last updated.
lastupdateby Name of the user who last updated the user.
lastupdatebyid UserID of the user who last updated the user.
lname The user's last name.
mobilephone The user's mobile phone number.
notes The user's notes.
password The user's encrypted password.
passwordcreated Date/time the user's password was last updated.
photofileext The file extension of the user's photo.
photofileid A unique identifier for the user's photo.
primaryaddressid The unique identifier for the user's primary address.
remoteid A special field for developer's to use. May load the user by this field. It does not have to be unique. Typically, used to store a unique identifier to associate the user to an external data store.
s2 Whether the user is a "super admin".
siteid SiteID the user belongs to.
subtype The user's subtype.
type Whether the user is a group (1) or user (2).
userid A unique identifier for the user.
username The user's username.
website The user's website address.

Helper Methods

When working with users, the following user bean/object's helper methods may be quite useful.

isInGroup('{groupName}')

Checks to see if the user is a member of a specific group.

<cfif userBean.isInGroup('admin')>
  <!--- User is a member of the 'admin' group --->
<cfelse>
  <!--- User is NOT a member of the 'admin' group --->
</cfif>

getFullName()

Concatenates the user's first name and last name.

<cfoutput>
  #esapiEncode('html', userBean.getFullName())#
</cfoutput>

getMembershipsIterator()

Returns an iterator of the groups the user belongs to.

<cfset it = userBean.getMembershipsIterator()>

<h3>User Memberships</h3>
<!--- Loop over the iterator --->
<cfif it.hasNext()>
  <ul>
    <cfloop condition="it.hasNext()">
      <cfset item = it.next()>
      <li>
        #esapiEncode('html', item.get('groupname'))#
      </li>
    </cfloop>
  </ul>
<cfelse>
  <p>User does not belong to any groups.</p>
</cfif>

getMembershipsQuery()

Returns a recordset of the groups the user belongs to.

<cfset rsMemberships = userBean.getMembershipsQuery()>

getInterestGroupsIterator()

Returns an iterator of interest groups the user has been assigned to.

<cfset it = userBean.getInterestGroupsIterator()>

<h3>User Interests</h3>
<!--- Loop over the iterator --->
<cfif it.hasNext()>
  <ul>
    <cfloop condition="it.hasNext()">
      <cfset item = it.next()>
      <li>
        #esapiEncode('html', item.get('name'))#
      </li>
    </cfloop>
  </ul>
<cfelse>
  <p>User does not have any interests.</p>
</cfif>

getInterestGroupsQuery()

Returns a recordset of the groups the user belongs to.

<cfset rsInterestGroups = userBean.getInterestGroupsQuery()>

getAddressesIterator()

Returns an iterator of the user's addresses.

<cfset it = userBean.getAddressesIterator()>

<h3>User Addresses</h3>
<!--- Loop over the iterator --->
<cfif it.hasNext()>
  <ul>
    <cfloop condition="it.hasNext()">
      <cfset item = it.next()>
      <li>
        #esapiEncode('html', item.get('addressname'))#
      </li>
    </cfloop>
  </ul>
<cfelse>
  <p>User does not have any addresses.</p>
</cfif>

getAddressesQuery()

Returns a recordset of the user's addresses.

<cfset rsUserAddresses = userBean.getAddressesQuery()>

checkEmail('{emailAddress}')

Returns true if the email address being passed in is safe to use, meaning that it doesn't match any other user's email address. Otherwise, returns false, if the email address matches another Mura user account's email address.

<cfif userBean.checkEmail('steve@blueriver.com')>
  <!--- Safe to use --->
  <cfset userBean.set('email', 'steve@blueriver.com').save()>
<cfelse>
  <!--- Email address matches another user's email address --->
</cfif>

checkUsername('{username}')

Returns true if the username being passed in is safe to use, meaning that it doesn't match any other user's username. Otherwise, returns false, if the username matches another Mura user account's username.

<cfif userBean.checkUsername('steve')>
  <!--- Safe to use --->
  <cfset userBean.set('username', 'steve').save()>
<cfelse>
  <!--- Username matches another user's username --->
</cfif>

Group Bean

The group bean/object includes group-specific data, and includes a number of helper methods. For example, you can obtain an iterator of the users who belong to the group, etc.

Note: The group bean/object merely uses the user bean/object. However, it contains only group-specific information, and group-specific helper methods. 

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the group bean/object. Use whichever syntax feels best to you.

Loading the Bean

You can load a group bean/object by any of the following attributes:

  • groupid
  • groupname
  • remoteid
<cfset groupBean = m.getBean('group').loadBy(groupname='admin')>

Note: As mentioned in the previous note above, the group bean/object leverages the user bean/object. The type attribute will be 1 if a group, and 2 if a user.

The group bean/object's loadBy method allows for an optional second argument, labeled siteid. This is necessary when working with a group assigned to a different siteid than the site you are currently working with. For example, if you are working on "Site B" and your group was created under the "default" site, then you would have to load the user similar to the example below.

<cfset groupBean = m.getBean('group').loadBy(groupname='admin', siteid='default')>

Once you have a variable to reference the desired bean/object, you can use the example Getters and Setters below.

Getters

groupBean.get('attributeName')
groupBean.get{AttributeName}()
groupBean.getValue('attributeName')

Setters

groupBean.set('attributeName', 'someValue')
groupBean.set{AttributeName}('someValue')
groupBean.setValue('attributeName', 'someValue')

Usage

Use the group bean/object to access and/or manipulate a Mura group.

Attributes

The table below lists available attributes.

Attribute Description
created Date/time the user was created.
email The groups's email address.
groupid The GroupID is a unique identifier for the group.
groupname The name of the group.
inactive Whether the group is inactive.
isnew Whether the group bean is new.
ispublic Whether the group is a Member Group (1) or System Group (0).
lastupdate Date/time the group was last updated.
lastupdateby Name of the user who last updated the user.
lastupdatebyid UserID of the user who last updated the user.
remoteid A special field for developer's to use. May load the group by this field. It does not have to be unique. Typically, used to store a unique identifier to associate the group to an external data store.
siteid SiteID the group belongs to.
subtype The group's subtype.
tablist A comma-delimited list of content editing tabs the group has access to.
type Whether the user is a group (1) or user (2).

Helper Methods

When working with groups, the following group bean/object's helper methods may be quite useful.

getMembersIterator()

Returns an iterator of the users who belong to the group.

<cfset it = groupBean.getMembersIterator()>

<h3>Group Members</h3>
<!--- Loop over the iterator --->
<cfif it.hasNext()>
  <ul>
    <cfloop condition="it.hasNext()">
      <cfset user = it.next()>
      <li>
        #esapiEncode('html', user.getFullName())#
      </li>
    </cfloop>
  </ul>
<cfelse>
  <p>Group does not have any members.</p>
</cfif>

getMembersQuery()

Returns a recordset of the users who belong to the group.

<cfset rsMembers = groupBean.getMembersQuery()>

Comment Bean

The comment bean/object includes comment-specific data. In addition, there are some comment-specific helper methods included such as whether the comment is approved, deleted, etc.

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the comment bean/object. Use whichever syntax feels best to you.

Loading the Bean

Load a comment bean/object by any of the following attributes:

  • commentid
  • remoteid
<cfset commentBean = m.getBean('comment').loadBy(commentid='{UUID}')>

Once you have a variable to reference the desired bean/object, you can use the example Getters and Setters below.

Getters

commentBean.get('attributeName')
commentBean.get{AttributeName}()
commentBean.getValue('attributeName')

Setters

commentBean.set('attributeName', 'someValue')
commentBean.set{AttributeName}('someValue')
commentBean.setValue('attributeName', 'someValue')

Usage

Use the comment bean/object to access and/or manipulate a comment.

Attributes

The table below lists available attributes.

Attribute Description
commentid A unique identifier for the comment.
comments The text of the comments.
contentid ContentID that the comment is associated with.
email Email address of the commenter.
entered Date/time of the comment.
flagcount Number of times the comment has been flagged as spam.
ip Internet Protocol (IP) address of the commenter.
isapproved Whether the comment is approved.
isdeleted Whether the comment is deleted.
isnew Whether the comment is new.
isspam Whether the comment is marked as spam.
kids Number of child comments.
name Name of the commenter.
parentid If the comment is a child, the ContentID of the parent comment.
path A comma-delimited path of ContentIDs to identify the ancestry of the comment.
siteid SiteID the comment belongs to.
subscribe Whether the commenter subscribed to future comments.
url URL the commenter entered.
userid UserID of the user who entered the comment.

Category Bean

The category bean/object includes category-specific data. This bean/object contains information about a category itself, and does not describe any relationships to content items themselves.

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the category bean/object. Use whichever syntax feels best to you.

Loading the Bean

Load a category bean/object by any of the following attributes:

  • categoryid
  • name
  • remoteid
  • filename
  • urltitle
<cfset categoryBean = m.getBean('category').loadBy(name='Mura CMS')>

Once you have a variable to reference the desired bean/object, you can use the example Getters and Setters below.

Getters

categoryBean.get('attributeName')
categoryBean.get{AttributeName}()
categoryBean.getValue('attributeName')

Setters

categoryBean.set('attributeName', 'someValue')
categoryBean.set{AttributeName}('someValue')
categoryBean.setValue('attributeName', 'someValue')

Usage

Use the category bean/object to access and/or manipulate a category.

Attributes

The table below lists available attributes.

Attribute Description
categoryid A unique identifier for the category.
datecreated Date/time the category was created.
filename URL-friendly path of the category.
isactive Whether the category is active.
isfeatureable Whether the category is able to be featured.
isinterestgroup Whether the category is an interest group.
isnew Whether the category is new.
isopen Whether the category allows content assignments.
lastupdate Date/time the category was last updated.
lastupdateby Name of the user who last updated the category.
name Name/title of the category.
notes Notes for the category.
parentid If category is a child, the CategoryID of the parent category.
path A comma-delimited path of CategoryIDs to identify the ancestry of the category.
restrictgroups A comma-delimited list of groups allowed to assign content to the category.
siteid SiteID of the category.
urltitle URL-friendly title/name of the category.

Feed Bean

The feed bean/object allows developers to programmatically query Mura for other beans/objects. Initially, many developers query for content beans/objects. In essence, when you search for content items using this method, you're creating a Collection dynamically. However, you may also query for user beans/objects, and as you'll see in the Custom Objects section, any other kind of Mura object or custom object you wish.

In short, the feed bean/object to obtains a collection of beans/objects, based on desired filters/criteria.

Note: Once the feed bean/object has been populated, most developers will call either the getIterator or getQuery methods to work with the collection of beans/objects. See the Key Methods area below for details. Please visit the Mura Iterators section, for more information on iterators.

Syntax

There are a couple of ways to obtain a feed bean/object, and each of those are described below.

loadBy

The first way for obtaining a feed bean/object is by using the common loadBy method. When loading it this way, keep in mind you will only be working with content beans/objects.

If you wish to load an existing Collection created via Mura's Admin UI, you can load a feed bean/object by any of the following attributes:

  • feedid
  • name
  • remoteid
<cfset feedBean = m.getBean('feed').loadBy(name='{Collection Name Goes Here}')>

getFeed

The primary method for obtaining a feed bean/object, is to use your desired bean's/object's getFeed method. You can either call getFeed on your desired bean/object itself, or pass in the name of the bean as an argument to the getFeed method, as shown in the examples below.

Content Feed
feedBean = m.getBean('content').getFeed();
// or
feedBean = m.getFeed('content');
User Feed
feedBean = m.getBean('user').getFeed();
// or
feedBean = m.getFeed('user');
Custom Object
feedBean = m.getBean('yourCustomObject').getFeed();
// or
feedBean = m.getFeed('yourCustomObject');

Usage

Use the feed bean/object to create, access, and/or manipulate a collection of beans/objects.

Key Methods

Since a feed bean/object is essentially an easy way to query Mura for objects, the key methods for working with feeds share a similarity with conventional SQL syntax, but in a way that's more comfortable for developers. Also, as shown in the examples below, Mura allows for method chaining. The methods below also apply to Mura ORM Feeds, and are also exposed via the Mura.js API.

Method Parameter(s) Description
where property Analogous to SQL "WHERE" clause. If property parameter is empty, the method is used for readability purposes only. You may optionally provide a property argument, in which case Mura will treat it as andProp.
prop property Analogous to SQL "AND" clause. The property argument is the attribute to use as the left operand value of a SQL WHERE condition.
andProp property Analogous to SQL "AND" clause. The property argument is the attribute to use as the left operand value of a SQL WHERE condition.
orProp property Analogous to SQL "OR" clause. The property argument is the attribute to use as the left operand value of a SQL WHERE condition.
null n/a Analogous to SQL "IS NULL" operator. Checks if the preceding property value is null.
isEQ criteria Analogous to SQL "=" comparison operator. Checks if the preceding property value is "equal to" the criteria argument.
isNEQ criteria Analogous to SQL "<>" or "!=" comparison operator. Checks if the preceding property value is "not equal to" the criteria argument.
isLT criteria Analogous to SQL "<" comparison operator. Checks if the preceding property value is "less than" the criteria argument.
isLTE criteria Analogous to SQL "<=" comparison operator. Checks if the preceding property value is "less than or equal to" the criteria argument.
isGT criteria Analogous to SQL ">" comparison operator. Checks if the preceding property value is "greater than" the criteria argument.
isGTE criteria Analogous to SQL ">=" comparison operator. Checks if the preceding property value is "greater than or equal to" the criteria argument.
isIn criteria Analogous to SQL "WHERE IN" clause. Checks if the preceding property value is in the list of literal values that have been specified as the criteria argument. Shorthand for multiple OR conditions.
isNotIn criteria Similar to the isIn method. Checks if the preceding property value is NOT in the list of literal values that have been specified as the criteria argument. Shorthand for multiple AND x NEQ conditions.
containsValue criteria Analogous to SQL "CONTAINS" comparison operator. Checks if the preceding property value "contains" the criteria argument.
beginsWith criteria Analogous to SQL "LIKE" comparison operator. Checks if the preceding property value "begins with" the criteria argument. May use wildcards (e.g., % or _, etc.)
endsWith criteria Analogous to SQL "LIKE" operator. Checks if the preceding property value "ends with" the criteria argument. May use wildcards (e.g., % or _, etc.)
openGrouping n/a Analogous to SQL "AND (" logical operator. Creates an "AND" with a parenthesis to form complex expressions. See grouping example below.
andOpenGrouping n/a Analogous to SQL "AND (" logical operator. Creates an "AND" with a parenthesis to form complex expressions. See grouping example below.
orOpenGrouping n/a Analogous to SQL "OR (" logical operator. Creates an "OR" with a parenthesis to form complex expressions. See grouping example below.
closeGrouping n/a Analogous to SQL ")" logical operator. Creates a closing parenthesis to preceding "opening" statements for complex expressions. See grouping example below.
sort property, direction Analogous to SQL "ORDER BY" clause. Allows sorting by one or more properties, and may be returned in ascending (asc) or descending (desc) order.
itemsPerPage itemsPerPage Expects a number to set the NextN attribute of the recordset. Set to zero (0) to include all items on one page.
maxItems maxItems Analogous to SQL "TOP" or "LIMIT" clause. Used to limit the number of records to retrieve. Set to zero (0) to retrieve all records. The default setting is twenty (20) for content beans/objects.
includeHomePage boolean *Only applies to Mura content.
Set to true to include the Home Page.
showNavOnly boolean *Only applies to Mura content.
Set to true to include only content items flagged as "Include in Site Navigation".
showExcludeSearch boolean *Only applies to Mura content.
Set to true to include content items flagged as "Exclude from Site Search".
isFeaturesOnly boolean *Only applies to Mura content.
Set to true to only search for content items flagged as "Feature in this section?".
contentPools criteria *Only applies to Mura content.
A comma-delimited list of SiteIDs to search for content items.
getIterator   Returns an iterator object. Please visit the Mura Iterators section, for more information on iterators.
 
Note: This method is not exposed or available via the Mura.js API. Use getQuery instead.
getQuery countOnly Returns a query object. Optionally pass in the countOnly argument, to obtain only a count of the records that match your filter criteria.
aggregate type, property

Use this method to aggregate queries/recordsets. This method helps by eliminating the need to write custom helper methods with queries against Mura ORM generated schema. See examples below. Added v7.1

Valid type options:

  • count
  • sum
  • min
  • max
  • avg
  • groupby

 

Examples

Note: When using m.getFeed('content'), unless you specify otherwise, Mura will only search for content items that are active, approved, set to appear in navigation, not excluded from search results, currently on display, exclude the home page, and limited to the top 20 records.

Also, when using m.getFeed('user'), by default, Mura will only search for Site Members (isPublic=1). To search for System Users, add .setIsPublic(0) to your method chain.

prop & andProp

This example demonstrates the use of the prop and andProp methods.

feedBean = m.getFeed('content')
            .where()
            .prop('title')
            .isEQ('About Us')
            .andProp('siteid')
            .isEQ('default');

// Analogous SQL
SELECT *
FROM tcontent
WHERE title = 'About Us'
  AND siteid = 'default';

orProp

This example demonstrates the use of the prop method.

feedBean = m.getFeed('content')
            .where()
            .prop('title')
            .isEQ('About Us')
            .orProp('title')
            .isEQ('News');

// Analogous SQL
SELECT *
FROM tcontent
WHERE title = 'About Us'
   OR title = 'News';

Sort

This example demonstrates how to obtain a feed bean/object of Mura content items. It is searching for any content where the "title" attribute is equal to "News" or "Blog" and will sort the results by title, descending.

contentFeed = m.getFeed('content')
               .where()
               .prop('title')
               .isEQ('News')
               .orProp('title')
               .isEQ('Blog')
               .sort('title', 'desc');

// Analogous SQL
SELECT *
FROM tcontent
WHERE title = 'News'
   OR title = 'Blog'
ORDER BY title DESC;

getIterator

Returns an iterator object.

<cfset it = feedBean.getIterator()>
<!--- Loop over the iterator --->
<cfif it.hasNext()>
  <ul>
    <cfloop condition="it.hasNext()">
      <cfset item = it.next()>
      <li>
        <cfdump var="#item.getAllValues()#">
      </li>
    </cfloop>
  </ul>
<cfelse>
  <!--- Feed has no items --->
</cfif>

getQuery

Returns a query object.

rsObjects = feedBean.getQuery();

contentPools

This example demonstrates how to search more than one site for content items, under the same instance of Mura.

feedBean = m.getFeed('content')
            .where()
            .prop('credits')
            .containsValue('Steve')
            .contentPools('site1,site2,site3');

// Analogous SQL
SELECT *
FROM tcontent
WHERE credits LIKE '%Steve%'
  AND siteid IN ('site1','site2','site3');

Grouping Example

This example demonstrates how to use the openGrouping, orOpenGrouping, and closeGrouping methods.

feedBean = m.getFeed('content')
            .where()
            .prop('credits')
            .containsValue('Steve')
            .openGrouping()
              .prop('title')
              .beginsWith('Why')
            .closeGrouping()
            .orOpenGrouping()
              .prop('title')
              .isEQ('News')
            .closeGrouping();

// Analogous SQL
SELECT *
FROM tcontent
WHERE credits LIKE '%Steve%'
  AND (
    title LIKE 'Why%'
  ) OR (
    title = 'News'
  );

Searching for Super Users

This example demonstrates how to search for "super" users. Remember, Mura only searches Site Members by default, so we have to use .setIsPublic(0) to search for System Users.

feedBean = m.getFeed('user')
            .where()
            .prop('s2')  // if s2=1, then they're a super user
            .isEQ(1)
            .setIsPublic(0);

// Analogous SQL
SELECT *
FROM tusers
WHERE s2 = 1
  AND ispublic = 0;

Searching for Custom Objects

This example demonstrates how to search for a custom object. See the Custom Objects section for more information.

feedBean = m.getFeed('yourCustomObject')
            .where()
            .prop('someProperty')
            .isEQ('someValue');

// Analogous SQL
SELECT *
FROM yourCustomObjectTable
WHERE someProperty = 'someValue';

Aggregate Examples

This example illustrates how to aggregate a fictitious "price" property of a "widget" object

feedBean = m.getFeed('widget')
            .aggregate('count', '*')
            .aggregate('sum', 'price')
            .aggregate('min', 'price')
            .aggregate('max', 'price')
            .aggregate('avg', 'price');

// get the query/recordset result
rsAggregatedWidgets = feedBean.getQuery();

// get an iterator of aggregated data
// NOTE: the beans in this iterator will be generic, and not actual widget beans
itAggregatedWidgets = feedBean.getIterator();

Mura Scope Objects

As noted in the Mura Scope section, in addition to the CFML scopes, Mura has its own scope called the Mura Scope. The Mura Scope also has a number of subscope objects, that are essentially wrappers of some of Mura's most common bean objects. In short, they are pre-populated beans, with their own special helper methods. The table below contains details on each of the Mura Scope's subscope objects.

Object Analogous Bean Description
m.globalConfig() configBean Wraps the configBean of the Mura instance in the current request. Includes instance-wide configuration data, such as data collected in the settings.ini.cfm file.
m.siteConfig() site Wraps the site bean of the site in the current request. Includes site configuration data collected via the Site Settings section in the administration area, as well as other useful site-specific information.
m.content() content Wraps the content bean of the content item in the current request. Includes data about a Mura content item, such as the title, summary, body, etc. In addition, there are several content-specific helper methods included. For example, you could get an iterator of any children of the content item, what specific categories the content item has been assigned to, etc.
m.currentUser() user* Wraps the sessionUserFacade for the user initiating the request. The object also has access to the user bean attributes, as well as some special session-specific data, such as whether the current user is logged in, whether the current user is a super user or admin user, etc.
m.event() n/a See the Mura "event" Scope section for details.

Inspecting Available Attributes

For each of the above subscope objects, using CFML's <cfdump> tag, you can easily inspect the available attributes and their values using the code examples below.

<cfdump var="#m.{subscope}().getAllValues()#">

<!--- For example --->
<cfdump var="#m.globalConfig().getAllValues()#">
<cfdump var="#m.siteConfig().getAllValues()#">
<cfdump var="#m.content().getAllValues()#">
<cfdump var="#m.currentUser().getAllValues()#">
<cfdump var="#m.event().getAllValues()#">
<!--- etc. --->

globalConfig

The globalConfig is a wrapper of Mura's configBean object, and is a subscope object of the Mura Scope. It includes instance-wide configuration data, such as data collected in the settings.ini.cfm file.

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the globalConfig. Use whichever syntax feels best to you.

Getters

m.globalConfig('attributeName')
m.globalConfig().get('attributeName')
m.globalConfig().get{AttributeName}()
m.globalConfig().getValue('attributeName')

Setters

m.globalConfig('attributeName', 'someValue')
m.globalConfig().set('attributeName', 'someValue')
m.globalConfig().set{AttributeName}('someValue')
m.globalConfig().setValue('attributeName', 'someValue')

Note: Setting any values with globalConfig are only temporary, and last for the duration of the request. In other words, calling the save method on globalConfig will not save any values.

Returns

A populated configBean object.

Usage

Use this scope to access global configuration attributes.

Attributes

See the Config Bean section for details on available attributes.

 

siteConfig

The siteConfig is a wrapper of Mura's site bean object, and is a subscope object of the Mura Scope. It includes site configuration data collected via the Site Settings section in the administration area, as well as other site-specific information.

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the siteConfig. Use whichever syntax feels best to you.

Getters

m.siteConfig('attributeName')
m.siteConfig().get('attributeName')
m.siteConfig().get{AttributeName}()
m.siteConfig().getValue('attributeName')

Setters

m.siteConfig('attributeName', 'someValue')
m.siteConfig().set('attributeName', 'someValue')
m.siteConfig().set{AttributeName}('someValue')
m.siteConfig().setValue('attributeName', 'someValue')

Returns

A populated site bean/object.

Usage

Use this scope to access "site" configuration attributes.

Attributes

See the Site Bean section for details on available attributes.

content

The content object is a wrapper of Mura's content bean object, and is a subscope object of the Mura Scope. It wraps the content bean of the content item being served in the current request. It includes data about a Mura content item, such as the title, summary, body, etc. In addition, there are several content-specific helper methods included. For example, you could get an iterator of direct children of the content item, what specific categories the content item has been assigned to, etc.

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the content object. Use whichever syntax feels best to you.

Getters

m.content('attributeName')
m.content().get('attributeName')
m.content().get{AttributeName}()
m.content().getValue('attributeName')

Setters

m.content('attributeName', 'someValue')
m.content().set('attributeName', 'someValue')
m.content().set{AttributeName}('someValue')
m.content().setValue('attributeName', 'someValue')

Returns

A populated content bean/object.

Usage

Use this scope to access information about the content item being served in the current request.

Attributes

See the Content Bean section for details on available attributes.

Helper Methods

See the Content Bean section for details on available helper methods..

currentUser

The currentUser object is a wrapper of the sessionUserFacade, and is a subscope object of the Mura Scope. Under the hood, Mura allows for access to the user bean/object attributes, as well as some special session-specific data, such as whether the current user is logged in, whether the current user is a super user or admin user, etc.

Syntax

The following examples illustrate how to "get" and/or "set" various attributes of the sessionUserFacade bean/object. Use whichever syntax feels best to you.

Getters

m.currentUser('attributeName')
m.currentUser().get('attributeName')
m.currentUser().get{AttributeName}()
m.currentUser().getValue('attributeName')

Setters

m.currentUser('attributeName', 'someValue')
m.currentUser().set('attributeName', 'someValue')
m.currentUser().set{AttributeName}('someValue')
m.currentUser().setValue('attributeName', 'someValue')

Returns

A populated sessionUserFacade bean/object.

Usage

Use this scope to access information about the user of the site in the current request.

Attributes

See the User Bean section for details on available attributes.

Helper Methods

In addition to the user bean/object's helper methods, the currentUser object has some special helper methods of its own.

isLoggedIn()

Returns true if the user is logged in. Otherwise, returns false if the user is logged out.

<cfif m.currentUser().isLoggedIn()>
  <!--- User IS logged in --->
  <h3>Hello, #esapiEncode('html', m.currentUser('fname'))#!</h3>
<cfelse>
  <!--- Use is NOT logged in --->
  <h3>Who are you?</h3>
</cfif>

isSuperUser()

Returns true if the user is a "super" user. Otherwise, returns false.

<cfif m.currentUser().isSuperUser()>
  <!--- User IS a 'super' user --->
<cfelse>
  <!--- Use is NOT a 'super' user --->
</cfif>

isAdminUser()

Returns true fi the user is an "admin" user. Otherwise, returns false.

<cfif m.currentUser().isAdminUser()>
  <!--- User IS an 'admin' user --->
<cfelse>
  <!--- Use is NOT an 'admin' user --->
</cfif>

Custom Objects

In addition to Mura's beans and objects, developers are able to create their own custom beans and objects. This section will walk you through a couple of different processes for creating your own custom objects.

The path you ultimately choose depends on whether you want to simply add some custom fields to one or more of Mura's common bean objects (i.e. content bean, user bean, group bean, site bean, etc.), or if you want to create a completely new, custom object altogether.

If you're merely looking to customize one of Mura's common bean objects, then you'll want to use Class Extensions. If you desire creating a completely new, custom object altogether, you'll definitely want to take a look at using Mura ORM.

 

Class Extensions

Mura's Class Extensions allow you to customize some of its common bean objects such as content beans, user beans, group beans, and site beans. The term "class extension" itself is borrowed from the world of object-oriented programming (OOP). These "objects" are designed in hierarchies, commonly referred to as a "class" hierarchy. Hence, "class extensions" is a term Mura uses to define custom subclasses.

Class extensions allow you to create Extended Attribute Sets (think fieldsets, or groups of related form elements) to provide additional "attributes" (think form fields) to collect and store data. In addition, you can create Related Content Sets to allow content managers the ability to associate content to something other than the default catch-all "Related Content" field, allowing you to create fields such as Related Videos, Related Files, Related Authors, and so on.

Also, class extensions provide an excellent way to allow developers the ability to target a certain Type and/or Subtype of a content item's body area, so they can do things such as automatically alter the layout of the body area, and/or include additional data, etc. Using this method means you wouldn't necessarily have to create any Extended Attribute Sets or Related Content Sets either, unless that's something you desire.

Types & Subtypes

Each of the bean objects Mura exposes for customization (see table below) include two very important attributes: Type, and Subtype. While you can change the Subtype attribute of a bean object, you cannot alter the Type attribute itself.

When working with class extensions, you first target the specific Type for customization. Then, you target the "default" Subtype, or create a new Subtype altogether. These are often represented as {Type}/{Subtype} when creating new objects. For example, "Folder/Locations", "Page/Location", "User/Employee", etc.

While the options for customization are essentially limitless, here are a few examples to help illustrate how you might use class extensions.

  • User
    • You could create a new "User" subtype, such as "Employee". Then, you might want to collect additional data about the employee such as "Emergency Contact Name", "Emergency Contact Mobile", etc.
  • Folder
    • You could create a new "Folder" subtype, such as "Locations". Then, you could target any content items using "Folder/Locations" as the Type and Subtype in order to loop over any child content items and display them on a map. You wouldn't necessarily have to add any Extended Attribute Sets or Related Content Sets either. As you'll see in the Define with the Admin UI section, you can also restrict the {Type}/{Subtype} of content that can be added as children.
  • Page
    • Along the same lines of the previous Folder example, you could create a new "Page" subtype, such as "Location". Then, you could collect data about the location such as the Street, City, State, Phone Number, etc. and display the information entered into these fields on the page when it's being rendered. In addition, you could use this data to geocode the location for use on map.

The "default" Subtype

By targeting "default" as the Subtype, any Extended Attribute Sets or Related Content Sets associated with the class extension will apply to all objects sharing the same Type attribute.

For example, if you create a new class extension and the Type equals "Page" and Subtype equals "Default", then anything you create will apply to all "Page/Default" content items, as well as any other "Page/{Anything}" content items.

Extendable Bean Objects

The table below itemizes each of the "Base Types" of bean objects available for customization.

Type Bean Description
Page content This is the standard Page content type.
Folder content This is the standard Folder content type.
File content This is the standard File content type.
Calendar content This is the standard Calendar content type.
Link content This is the standard Link content type.
Component content This is a standard Component, which is essentially a special type of content itself. Using Class Extensions with Components opens several possibilities such as creating a Component with tabbed content, slideshows, and more.
Form content This is a standard Form, also a special type of content.
Base content Extending the Base/Default object allows you to create additional Extended Attribute Sets and Related Content Sets to appear on all standard content types (Page, Folder, File, Calendar, and Link), excluding Components and Forms. If you specify a different Subtype, then any Extended Attribute Sets or Related Content Sets will only appear on content types that share the specified Subtype.
User (2) user Since the group bean is essentially the user bean, the type attribute for users is technically stored as a "2" to indicate the record reflects a "user".
Group (1) group Since the group bean is essentially the user bean, the type attribute for groups is technically stored as a "1" to indicate the record reflects a "group".
Address address Address bean objects are related to user beans. A user may have one or more addresses. By extending this class, you can create additional attributes to store new types of data that Mura doesn't already collect.
Site site Extending the Site object allows you to create additional Extended Attribute Sets via the Site Settings area of the back-end administration area of Mura.

 

Define with Admin UI

Follow the steps below to create a custom class extension. For example purposes, we'll create a Page/Location, as mentioned in the introduction to Class Extensions.

  1. From Mura's back-end administration area, select Site Settings, click Class Extensions, and select Add Class Extension.
  2. You should be taken to the Add Class Extension screen.
    • Base Type
      • Please refer to the Extendable Bean Objects section of the Class Extensions page for details on each option.
    • Description
      • You may enter your desired description of the class extension here. This is merely information for anyone else who may edit or manage the class extension in the future, and is not displayed anywhere else by default.
    • Status
      • Active
        • If selected, the defined Class Extension will appear as an option for content managers when creating new content items.
      • Inactive
        • If selected, the defined Class Extension will not appear as an option for content managers when creating new content items.
  3. From the Add Class Extension screen, click the Base Type menu, and choose your desired option, (e.g., Page).
  4. Once you've made a selection, additional form fields may appear. If you select one of the content types, (e.g., Page, Folder, etc.), additional form fields will appear.
    • Sub Type
      • You may choose to leave the initial setting of "Default" so that any Extended Attribute Sets and/or Related Content Sets will apply to all content items sharing the same Type. Or, you may enter your own, unique Subtype.
    • Icon
      • The icon you select here, will appear in the Select Content Type dialog window, when content managers create new content items.
    • Show "Summary" field when editing?
      • Select whether you wish to display the "Summary" field.
    • Show "Body" field when editing?
      • Select whether you wish to display the "Body" field.
    • Show "Associated Image" field when editing?
      • Select whether you wish to display the "Associated Image" field.
    • Allow user to add only specific Subtypes?
      • If Yes, you may select one, or more options from the available list. This will restrict what appears in the Select Content Type dialog window, when content managers add new content items as children on this specific type of content.
  5. When finished, click the Add button, so save your new Class Extension.
  6. You should now be taken to the Class Extension screen, where you may view/create Extended Attribute Sets, and Related Content Sets.

Extended Attribute Sets

Extended Attribute Sets are essentially <fieldset> elements. In other words, they're a set of form controls, grouped under a common name. To create an Extended Attribute Set, follow the steps outlined below.

  1. From the back-end administration area of Mura, select Site Settings, click Class Extensions, and select Class Extensions.
  2. You should be directed to the Class Extensions screen.
  3. Select the Class Extension you wish to add an Extended Attribute Set to, from the listing of available Class Extensions.
  4. You should be directed to the Class Extension screen. Here, you can view any available Extended Attribute Sets or Related Content Sets.
  5. To add an Extended Attribute Set, click the Add button, then select Add Attribute Set.
  6. You should now see the Add Attribute Set screen.
    • Attribute Set Name
      • The text entered here will be used as the <legend> for the generated <fieldset>.
    • Container (Tab)
      • You may select the tab you wish to include your Extended Attribute Set on, from the listing of available tabs. The listing will differ, depending on the Base Type you selected when creating the Class Extension itself.
      • If you select the Custom UI option, you're essentially telling Mura that you'll take care of collecting any attributes you're going to define. If you wish to add a new tab, and include a custom form for collecting the data, you may find this Gist useful: https://gist.github.com/stevewithington/f3dd405d5a188fb594a1
  7. Once you've entered an Attribute Set Name, and selected your desired Container (Tab), click the Add button to create your new attribute set.
  8. You should be directed to the Manage Extended Attribute Set screen. This is where you'll add, and manage your new attributes, or form fields.
  9. To create a new attribute, click the Add New Attribute button.
  10. The screen should now reveal a form to add a new attribute.
    • Name (No spaces)
      • Text entered here will be used as the name attribute of the form field. In addition, the text entered here is how you will reference any data entered for this attribute, as you'll see in the Displaying Extended Attributes section. It is important to use a proper naming convention, as if you were manually creating the input using HTML. Keep in mind that this form field will be included on a much larger form, and as such, you'll want to avoid using any of the bean object's attribute names so you don't run into any naming collisions. For example, you don't want to use the Name "title", since Content Beans already have an attribute labeled "title".
      • The recommended best practice is to prefix the Name with the Subtype of your class extension. For example, if your Subtype equals "Location", instead of using "title" for the Name, you might use "locationtitle" for the Name.
    • Label
      • Text entered here will be used as the <label> element.
    • Input Type
      • Select your desired input type from the option list.
    • Default Value
      • Optionally, enter a default value here. To include a dynamic value, you may use Mura [m] tags.
    • Tooltip
      • Optionally, enter text to be used as a tooltip.
    • Required
      • Whether the field is required. If True, Mura will use the option selected in the Validate field when the user submits the form.
    • Validate
      • If you desire the input to be validated before the form is submitted, select one of the following options.
        • None
          • Do not validate input.
        • Date
          • Validates data entered is a valid date. Mura will display a calendar UI widget for content managers to use when completing this form field.
        • DateTime
          • Validates data entered is a valid date and time. Mura will display a calendar and time UI widget for content managers to use when completing this form field.
        • Numeric
          • Validates data entered is an integer.
        • Email
          • Validates data entered matches standard email address formats.
        • Regex
          • Validates data entered against the JavaScript regular expression entered in the Regex field.
        • Color
          • If the Input Type is set to TextBox, and this option is selected, Mura will display a "color picker" UI widget for content managers to use when completing this form field.
        • URL
          • Validates data entered matches standard URL formats.
    • Regex
      • If Validate is set to Regex, Mura will use the JavaScript regular expression entered here to validate data entered in this form field.
    • Validation Message
      • If Required is set to True, text entered here will be displayed to content managers if the data entered in this form field does not pass validation rules.
    • Option List ("^" Delimiter)
      • This carat ("^") delimited list of "option values" will be used if Input Type is set to SelectBox, MultiSelectBox, or RadioGroup. For example, "option1^option2^option3". To include a dynamic value, you may use Mura [m] tags.
    • Option Label List (Optional, "^" Delimiter)
      • This carat ("^") delimited list of "option labels" will be used if Input Type is set to SelectBox, MultiSelectBox, or RadioGroup. For example, "Option 1^Option 2^Option 3". To include a dynamic value, you may use Mura [m] tags.
    • For Administrative Use Only?
      • If Yes, the field will not display for content editing purposes, and will be a hidden form field.
  11. After you've completed the form, click the Add button to create your new attribute.
  12. Repeat these steps to create additional attributes for the Extended Attribute Set.
  13. The attributes sort order is the order in which they will be displayed to content managers. If you wish to reorder any of them, click the Reorder button.
  14. Then, hover over the attribute you wish to move, and then click, drag, and drop to your desired location.
  15. When finished reordering, click the Save Order button.

Define with XML

In the Define with Admin UI section, we covered creating Class Extensions, Extended Attribute Sets, and Related Content Sets using Mura's back-end administrator user interface. In addition to using the administrator's UI, Mura can parse a special XML file to create Class Extensions, as well as create custom image sizes, and more.

config.xml.cfm

Whenever Mura experiences an application reload, it scans for the config.xml.cfm file, and if found, will attempt to parse the file to create any pre-defined Class Extensions and custom image sizes. As you'll see in the Mura Modules section and Plugins section, if the file is located under a modules or plugin directory, Mura uses the file to obtain various settings and information about the module or plugin too.

Convention-Based Lookup

The config.xml.cfm file will be discovered in any theme directory, module directory, content type directory, or plugin directory.

For example:

  • {context}/themes/{ThemeName}/
  • {context}/themes/{ThemeName}/content_types/{Type}/
  • {context}/themes/{ThemeName}/content_types/{Type}_{Subtype}/
  • {context}/themes/{ThemeName}/modules/{Module}/
  • {context}/sites/{SiteID}/themes/{ThemeName}/
  • {context}/sites/{SiteID}/themes/{ThemeName}/content_types/{Type}/
  • {context}/sites/{SiteID}/themes/{ThemeName}/content_types/{Type}_{Subtype}/
  • {context}/sites/{SiteID}/themes/{ThemeName}/modules/{Module}/
  • {context}/plugins/{PluginName}/plugin/
  • {context}/plugins/{PluginName}/modules/{Module}/
  • {context}/plugins/{PluginName}/content_types/{Type}_{Subtype}/

As covered in the Mura Rendering section, you can nest additional module directories and content type directories within each other, and Mura will automatically search for the config.xml.cfm file in those too.

Please refer to the Elements of the "config.xml.cfm" File section for details about the file itself.

 

Elements Of The "config.xml.cfm" File

At the top level, a config.xml.cfm document should contain the mandatory <mura> element. There are no attributes available for this element, unless being used with a module/display object.

The following table describes available attributes, only if used with a module/display object.

Attribute Req/Opt Default Description
name Required   This is the actual name or title of the module/display object.
contenttypes Optional empty string If blank, it will never display as a draggable option. You may use the asterisk (*) to indicate the display object may be used on all content types. Or, you may pass in a comma-delimited list of content types the display object may be used on. For example, contenttypes="{Type | Type/Subtype},Folder/Blog,Folder/News".
omitcontenttypes Optional empty string You may use the asterisk (*) to indicate the display object should not be used on any content types. Or, you may pass in a comma-delimited list of content types the display object should not be used on. For example, contenttypes="{Type | Type/Subtype},Folder/Blog,Folder/News".
condition Optional true You may pass in a condition to be evaluated at runtime as to whether the display object should be available. For example, condition="(m.content('title') == 'News')"
iconclass Optional mi-cog You may use a Fontawesome icon class, prefixed with "mi-" instead of "fa-" to avoid potential conflicts. For example, iconclass="mi-book".  The icon specified here will be used to identify the display object.
cacheoutput Optional true If false, output will not be cached, when Site Caching is enabled.

Example <mura>

This attributes will only be used with a display object.

<mura name="My Display Object" contenttypes="*" iconclass="mi-book">
  ...
</mura>

Subordinate to the <mura> element is an <imagesizes> element, which may contain one or more custom image sizes, and an <extensions> element, which may contain one or more custom class extension definitions.

<mura>
    <imagesizes>
    </imagsizes>
    <extensions>
    </extensions>
</mura>

Note: Plugins have additional elements, and will be covered in the Plugin Development section.

<imagesize> is a sub-element of <imagesizes>

The following table describes the available attributes.

Attribute Req/Opt Description
name Required Treat the value of this attribute as a variable name. In other words, do not include any spaces or special characters.
width Required Specify the numeric width in pixels.
height Required Specify the numeric height in pixels.

Example <imagesize>

<imagesize name="yourimagesizename" width="600" height="100"/>

<extension> is a sub-element of <extensions>

The following table describes the available attributes.

Attribute Req/Opt Description
type Required

The Base Type to apply the class extension to. Valid options are:

  • 1 (to indicate User Group)
  • 2 (to indicate User)
  • Address
  • Page
  • Folder
  • File
  • Calendar
  • Link
  • Component
  • Site
  • Base
subtype Required Use "default" to apply the class extension to all, or enter a custom subtype. Does not apply to the Site type.
availablesubtypes Optional Answers the question; "Allow users to add only specific subtypes?". Leave blank to allow all content types. Or, you may pass in a comma-delimited list of content types. For example, availablesubtypes="{Type | Type/Subtype},Folder/Blog,Folder/News".
description Optional May enter a description for the class extension.
hasassocfile Optional Answers the question; "Show 'Associated Image' field when editing?". Valid options are: 1 (yes/true), 0 (no/false). Default is "1".
hasbody Optional Answers the question; "Show 'Body' field when editing?". Valid options are: 1 (yes/true), 0 (no/false). Default is "1". Applies to Page, Folder, and Calendar.
hasconfigurator Optional Answers the question; "Show 'List Display Options' field when editing?". Valid options are: 1 (yes/true), 0 (no/false). Default is "1". Applies to Folder only.
hassummary Optional Answers the question; "Show 'Summary' field when editing?". Valid options are: 1 (yes/true), 0 (no/false). Default is "1". Applies to Page, Folder, File, Calendar, and Link.
iconclass Optional You may use a Fontawesome icon class, prefixed with "mi-" instead of "fa-" to avoid potential conflicts. For example, iconclass="mi-book".  The icon specified here will be used to identify the display object.
isactive Optional Answers the question; "Status". Valid options are: 1 (yes/true), 0 (no/false). Default is "1".

Example <extension>

<extension type="Page" subType="Product" hasSummary="1" hasBody="1" isActive="1">
	...
</extension>

<attributeset> is a sub-element of <extension>

An attribute set is similar to creating a <fieldset> element in HTML.

The following table describes the available attributes.

Attribute Req/Opt Description
name Required This will display on the content edit screen as the title or label above the grouping of associated attributes, similar to a fieldset's legend.
container Required This is the "tab" container which the grouping of associated attributes will be displayed on. Valid options depend on the content Type. See the Available Container Options table.
orderno Optional Specify the numeric

Available Container/Tab Options

Option Description
Basic Displays the attribute set on the Basic tab.
Default Displays the attribute set on the Extended Attributes tab. This is the default setting.
Custom Will not display the attribute set by default. This allows for a developer to create a custom user interface to collect the data.
List Display Options DIsplays the attribute set on the List Display Options tab.
Layout & Objects Displays the attribute set on the Layout & Objects tab.
Categorization Displays the attribute set on the Categorization tab.
Tags Displays the attribute set on the Tags tab.
Related Content Displays the attribute set on the Related Content tab.
Advanced Displays the attribute set on the Advanced tab.
Publishing Displays the attribute set on the Publishing tab.
Usage Report Displays the attribute set on the Usage Report tab.

Valid Container/Tab Options

The following table describes available options to use as the value for each Base Type.

Base Type Container/Tab Options
1 (User Groups), 2 (Users), & Site
  • Default
  • Custom
Pages, Folders, Links, Files, and Calendars
  • Basic
  • Default
  • List Display Options
  • Layout & Objects
  • Categorization
  • Tags
  • Related Content
  • Advanced
  • Publishing
  • Usage Report
  • Custom
Address, Custom, and Base
  • Basic
  • Default
  • Custom
Component
  • Basic
  • Default
  • Categorization
  • Usage Report
  • Custom

Example <attributeset>

<attributeset name="Mobile Options" container="Basic" orderno="1">
    ...
</attributeset>

<attribute> is a sub-element of <attributeset>

An attribute describes a data container (form field) and its validation rules.

The following table describes required and optional attributes of the <attribute> element:

Attribute Description
name The variable name. This will also become the form fields "name" attribute.
label The label that will be displayed on the form
hint A tooltip hint for the form field
type Valid options: TextBox (default), TextArea, HTMLEditor, SelectBox, MultiSelectBox, RadioGroup, File, Hidden
required Valid options: true, false (default)
validation Leave blank if not using validation. Otherwise, valid options are: Date, DateTime, Numeric, Email, Regex, Color, and URL.
regex If validation is set to Regex, then you can enter a JavaScript regular expression to execute when the form is submitted.
message The error message that displays when validation fails.
defaultvalue Optional. The default value for the form field.
optionlist A carat "^" delimited list of option values. Used when type is set to SelectBox, MultiSelectBox or RadioGroup.
optionlabellist A carat "^" delimited list of option labels. Used when type is set to SelectBox, MultiSelectBox or RadioGroup.
adminonly Valid options: 0 for false (default), 1 for true. Whether the attribute is for administrator use only, and will not be displayed.

Note: To enable a color picker for a form field, set type="TextBox" and validation="Color"

Example config.xml.cfm

<?xml version="1.0" encoding="UTF-8"?>
    <mura>
        <!-- Image Sizes -->
        <imagesizes>
          <imagesize
            name="locationimage"
            width="600"
            height="400"/>
        </imagesizes>

        <!-- Class Extensions -->
        <extensions>
            <extension 
                adminonly="0" 
                availablesubtypes="Page/Location" 
                description="" 
                hasassocfile="0" 
                hasbody="0" 
                hasconfigurator="0" 
                hassummary="0" 
                iconclass="mi-map-o" 
                subtype="Locations" 
                type="Folder"/>

            <extension 
                availablesubtypes="" 
                description="" 
                hasassocfile="1" 
                hasbody="0" 
                hasconfigurator="0" 
                hassummary="1" 
                iconclass="mi-map-pin" 
                subtype="Location" 
                type="Page">

                <attributeset 
                    container="Basic" 
                    name="Location Options" 
                    orderno="1">

                    <attribute 
                        adminonly="0" 
                        defaultvalue="" 
                        hint="" 
                        label="Location Street" 
                        message="Please enter a Location Street" 
                        name="locationstreet" 
                        optionlabellist="" 
                        optionlist="" 
                        orderno="1" 
                        regex="" 
                        required="true" 
                        type="TextBox" 
                        validation=""/>

                    <attribute 
                        adminonly="0" 
                        defaultvalue="" 
                        hint="" 
                        label="Location City" 
                        message="Please enter a Location City" 
                        name="locationcity" 
                        optionlabellist="" 
                        optionlist="" 
                        orderno="2" 
                        regex="" 
                        required="true" 
                        type="TextBox" 
                        validation=""/>

                    <attribute 
                        adminonly="0" 
                        defaultvalue="" 
                        hint="" 
                        label="Location State" 
                        message="Please enter a Location State" 
                        name="locationstate" 
                        optionlabellist="" 
                        optionlist="" 
                        orderno="3" 
                        regex="" 
                        required="true" 
                        type="TextBox" 
                        validation=""/>

                    <attribute 
                        adminonly="0" 
                        defaultvalue="" 
                        hint="" 
                        label="Location Postal Code" 
                        message="" 
                        name="locationpostalcode" 
                        optionlabellist="" 
                        optionlist="" 
                        orderno="4" 
                        regex="" 
                        required="false" 
                        type="TextBox" 
                        validation=""/>

                </attributeset>
            </extension>
        </extensions>
    </mura>

 

 

 

Export Definitions via Admin UI

Mura is able to export Class Extensions as an XML file via the back-end administration UI. This is the recommended method for creating XML Class Extension definitions, as opposed to writing the XML by hand. By using this method, you're able to reduce the likelihood of typos or introducing errors when Mura attempts to parse your XML file(s).

There are two methods for exporting Class Extensions. You can export them individually, or select multiple extensions to export as a single XML file.

Export Single Class Extension

To export a single Class Extension, follow the steps outlined below.

  1. From the back-end administration area of Mura, select Site Settings, click Class Extensions, and select Class Extensions.
  2. You should be directed to the Class Extensions screen.
  3. Select the Class Extension you wish to export, from the listing of available Class Extensions.
  4. You should be directed to the Class Extension screen.
  5. Click the Export Class Extension button.
  6. You should directed to the Export Class Extensions screen.
  7. You can hover over the code, and press <CTRL>+C on a PC, or <CMD>+C on a Mac to copy it to your clipboard, then paste the code into your own XML file.
  8. Or, you can simply click the Download button at the bottom of the screen, to download the code as a XML file.
  9. You now have a file that can be used to import the Class Extension into another instance of Mura, or package it with a display object's config.xml.cfm file or a plugin's config.xml.cfm file for future distribution.

Export Multiple Class Extensions

To export multiple Class Extensions at the same time, so they can be packaged together in a single XML file, follow the steps outlined below.

  1. From the back-end administration area of Mura, select Site Settings, then click Class Extensions, and select Export Extensions.
  2. Or, from the Class Extension screen, select the Actions button, then click Export.
  3. You should be directed to the Export Class Extensions screen.
  4. Select the Class Extensions you wish to export, or simply click Select All to check all available Class Extensions if you desire to do so.
  5. Click the Export button.
  6. You should now be directed to the Export Class Extensions screen.
  7. You can hover over the code, and press <CTRL>+C on a PC, or <CMD>+C on a Mac to copy it to your clipboard, then paste the code into your own XML file.
  8. Or, you can simply click the Download button at the bottom of the screen, to download the code as a XML file.
  9. You now have a file that can be used to import the Class Extension into another instance of Mura, or package it with a display object's config.xml.cfm file or a plugin's config.xml.cfm file for future distribution.

Import Definitions via Admin UI

To import Class Extensions, you will first need a properly formatted XML file, preferably exported via Mura's admin UI. Once you have a properly formatted XML file, follow the steps below to import the Class Extensions.

  1. From the back-end administration area of Mura, select Site Settings, click Class Extensions, then select Import Extensions.
  2. Or, from the Class Extensions screen, select the Actions button, and click Import.
  3. You should be directed to the Import Class Extensions screen.
  4. Click the Browse or Choose File button, then select navigate to the exported XML file.
  5. When ready, click the Import button.
  6. Mura will then upload, and attempt to parse the submitted XML file. When the import has completed, your new Class Extensions should appear in the list on the Class Extensions screen.

Displaying Extended Attributes

There are a few ways to display the attributes of Class Extensions, and it really depends on where you're attempting to display them. That said, the most important thing to keep in mind is that you'll need to know your attribute's name property, in order to display it.

In short, a Class Extension's attribute is treated as a property of the bean it's associated with. So, for example, if a Class Extension's Base Type is Content, then you could use the same getter and setter methods when working with any other attribute of a Content Bean.

Basic Syntax

The basic syntax is shown in the example below.

someBean.get('attributeName')
someBean.get{AttributeName}()
someBean.getValue('attributeName')

Examples

The examples listed below demonstrate the most common method for accessing attributes of a Class Extension. In addition, the recommended best practice is to use esapiEncode when outputting attributes.

Via Layout Template

This example assumes the Base Type is "Content", and you merely want to display the attribute on a layout template.

<cfoutput>
  <h2>
    #esapiEncode('html', m.content('attributeName'))#
  </h2>
</cfoutput>

Via HTML Editor

This example assumes you wish to output an attribute in the body of a HTML Editor.

[m]esapiEncode('html', m.content('attributeName'))[/m]

Via Content Bean

This example assumes you load a Content Bean, and then want to retrieve the data for whatever reason.

contentBean = m.getBean('content').loadBy(title='Home');
// assumes we have a custom attribute labeled `locationstreet`
street = contentBean.get('locationstreet');

Via Iterator

You can easily pull out attributes of Class Extensions while looping inside of a Mura Iterator.

<!--- get an iterator of the content item's children --->
<cfset it = m.content().getKidsIterator()>
<ul>
<cfloop condition="it.hasNext()">
  <cfset item = it.next()>
  <li>
    #esapiEncode('html', item.get('attributeName'))#
  </li>
</cfloop>
</ul>

Making Attributes Editable

When displaying an extended attribute in a layout template, you may want to make the attribute editable by content managers when they're using front-end editing features. This is accomplished by using  m.renderEditableAttribute.

Note: This feature only works on extended attributes with its Input Type set to TextBox or HTMLEditor.

Function Syntax

m.renderEditableAttribute(
  attribute
  , type
  , required
  , validation
  , message
  , label
  , value
  , enableMuraTag
)

Parameters

Parameter Type Req/Opt Default Description
attribute string required   The attribute's name
type string opt text

Valid options are:

  • text
    • Treats the attribute as text being entered into a TextBox
  • HTMLEditor
    • When editing content via inline edit mode, and a content manager double clicks into the text, a HTML Editor toolbar will appear.
required boolean opt false If true, Mura will require a value to be entered before saving successfully.
validation regex opt blank Leave blank, or enter a JavaScript regular expression to use for validation purposes. Will trigger if a value is entered and a save is attempted.
message string opt empty string The message to display when the submitted value does not pass validation.
label string opt attribute name Text to display above the field when edited.
value string opt the attribute's stored value Optionally pass in a string to preset the value.
enableMuraTag boolean opt false If true, the value will be parsed by Mura's setDynamicContent to render any Mura [m] tags.

Example

The following example demonstrates how to use m.renderEditableAttribute for an attribute with its Input Type set to HTMLEditor.

<cfoutput>
  <div>
    #m.renderEditableAttribute(
      attribute='attributeName'
      type='HTMLEditor'
      label='Attribute Label'
    )#
  </div>
</cfoutput>

Mura ORM

Before you proceed through this section, it's important to have at least a basic understanding of object-oriented programming (OOP) and its principles. It would be wise to take advantage of the plethora of resources, available both online and offline, before you continue in this section. Additionally, having a solid understanding of relational database management systems (RDBMSs) is extremely helpful when working through this section.

Object-Relational Mapping (ORM)

Since relational database management systems (RDBMSs) don't store objects directly, object-relational mapping (ORM), attempts to bridge the world to object-oriented programming (OOP). According to Wikipedia, ORM addresses the main issue for OOP developers who work with RDBMSs, by "translating the logical representation of objects into an atomized form capable of being stored in a database, while preserving the properties of objects and their relationships so they can be reloaded as objects when needed." In other words, ORM essentially creates a "virtual object database" that can be used by programmers.

What is Mura ORM?

Mura ORM is essentially a "virtual object database" that can be used by Mura developers. It allows developers the ability to create their own objects, and work with them in the same ways Mura developers can work with Mura's bean objects. This means developers don't have to worry about what kind of database Mura is running on, or write a ton of SQL to perform many of the most mundane tasks such as creating, reading, updating, or deleting objects and their associated database records.

While comparable in nature to ColdFusion ORM, Mura ORM is not exactly the same. However, if you've worked with ColdFusion ORM before, you will definitely find many similarities with Mura ORM.

Mura ORM Configuration

Mura employs a "convention over configuration" design paradigm for registering ORM objects/entities. So, instead of creating configuration files to describe the details of where your objects/entities reside, and how to instantiate them, Mura uses a convention-based approach. In other words, by placing your objects/entities in specifically named directories, you don't have to manually or explicitly register your entities.

Model Directory

Under the hood, Mura simply leverages DI/1, a simple convention-based dependency injection (inversion of control) framework. As such, any .CFC discovered under the "../model" directories identified below will automatically get registered with DI/1.

  • {context}/themes/{ThemeName}/model/
  • {context}/themes/{ThemeName}/content_types/{Type}/model/
  • {context}/themes/{ThemeName}/content_types/{Type}_{Subtype}/model/
  • {context}/themes/{ThemeName}/modules/{Module}/model/
  • {context}/sites/{SiteID}/model/
  • {context}/sites/{SiteID}/themes/{ThemeName}/model/
  • {context}/sites/{SiteID}/themes/{ThemeName}/content_types/{Type}/model/
  • {context}/sites/{SiteID}/themes/{ThemeName}/content_types/{Type}_{Subtype}/model/
  • {context}/sites/{SiteID}/themes/{ThemeName}/modules/{Module}/model/

You may also register any directory you want by using m.globalConfig().registerModelDir({dir}). The "dir" parameter is a logical path to a CFML directory.

This is typically done in the onApplicationLoad event. This is useful for plugins, since Mura does not automatically scan for a "model" directory in plugins, since some plugin developers may be using their own bean factory, and do not need Mura to auto-register them.

public any function onApplicationLoad(m) {
  // This is how you could register a 'model' directory in a plugin
  arguments.m.globalConfig().registerModelDir('/pluginName/path/to/your/model/');
}

All registered objects/entities are essentially "global" in the sense that they'll all use the same underlying database tables. So, you'll want to avoid describing the same entities in multiple sites. We'll cover more about entities in the Mura ORM Entity section.

The "beans" Directory

Any .CFC's discovered under "../model/beans/" will be registered as "transient" objects, not as "singleton" objects.

  • Transient objects exist only for a request and then are discarded. In other words, you et a new copy every time.
  • Singleton objects are shared among all threads and requests. In other words, there's only one of them, and you're not getting a new copy every time. These are great for "service" type objects.

The examples below show how you could register multiple transient objects.

  • ../model/beans/person.cfc
  • ../model/beans/personaddress.cfc
  • ../model/beans/personphonenumber.cfc

The "handlers" Directory

Any .CFC's discovered under a "../handlers/" directory within a "model" directory, will be registered as custom event handlers. The examples below show how you could register multiple custom event handlers, in various locations.

  • ../model/handlers/myhandler.cfc
  • ../model/services/handlers/myhandler.cfc

Registration

In order for Mura to discover these directories, and any subsequent changes you make to the directories or files contained within them, you'll need to reload Mura.

Also, the first time you reload, and anytime you add new properties to your entities, you'll need to append "&applydbupdates" to the URL in order for Mura to parse your objects/entities and make the appropriate changes to the database schema.

Mura ORM Entity

In a nutshell, a Mura ORM entity is described by creating a ColdFusion component (.CFC). Mura leverages some of the standard attributes of a Mura ORM component, and also utilizes some custom attributes, as outlined in the table below.

Attribute Req/Opt Default Description
bundleable Optional true If false, entities will not be included in any bundles.
cachename Optional   You may optionally supply a custom cache name to use when being stored in Mura's cache factory.
datasource Optional m.globalConfig('datasource') If you wish to use a datasource that's different from the one Mura uses by default, you may supply one here.
dbtype Optional  

If specifying a datasource attribute, specify the database type. Valid options include:

  • mysql
  • mssql
  • oracle
  • postgres
discriminatorcolumn Optional empty string You may specify a property to filter on by default.
discriminatorvalue Optional empty string If using a discriminatorcolumn, you may specify the property's criteria to filter on by default.
extends Required mura.bean.beanORM This attribute should always be present, and should always extend mura.bean.beanORM or mura.bean.beanORMHistorical
entityname Required   This is the name of the object/entity.
manageschema Optional true If false, Mura will not manage the underlying table for the entity, and you are assuming all responsibility for any schema changes.
orderby Optional   You may pass a comma-delimited list of properties to sort by.
public Optional false If true, allows the entity to be used via the JSON API by non-administrative users. If false, users must be logged in, and have access to the specific site in order to work with the entity.
readonly Optional false If true, Mura will not allow any new records to be added to the database, or any updates to existing records in the database.
scaffold Optional false If true, allows the entity to be managed via the Mura ORM Scaffolder.
table Required   Specify the name to use for a database table to store data about this entity.
usetrash Optional true If false, entities will not be moved to the Trash Bin, and will be hard deleted instead.

Example Mura ORM Component

component 
  extends="mura.bean.beanORM"
  entityname="something"
  table="somethings"
  bundleable="true"
  displayname="SomethingBean"
  public=true
  orderby="{someproperty}" {

  // Properties & Methods

}

Mura ORM Component Properties

To describe the various properties/attributes and relationships of Mura ORM entities, use CFML properties. The following table describes the available attributes for Mura ORM component properties.

Attribute Req/Opt Default Description
cascade Optional   If the property is a related entity and the value is "delete", when the parent entity/object is deleted, any related entities will also be deleted.
cfc Optional   If the property is a related entity, set to the related entity's "entityname" value.
comparable Optional true If false, the property will not be included in entity comparisons. For example:
entityDifferences = entityA.compare(entityB);
datatype Optional varchar

Valid options are:

  • datetime
  • int
  • text
  • tinyint
  • smallint
  • varchar
  • char
  • number
  • boolean
  • float
  • double
  • blob
default Optional   If the required attribute is set to "no", or not specified, you may supply a default value to use.
fieldtype Optional  

If property is a primary key, you should set fieldtype to "id". Mura will then create a UUID for each new object stored in the database.

If property is a related entity, you may specify the relationship type here. The left side of the "to" types listed below is the parent entity, and the right side of the "to" is the related entity. So, for example "one-to-many" would mean one parent entity could have many related entities, and so on. Valid options are:

  • one-to-one
  • one-to-many
  • many-to-one
  • many-to-many
  • index  (sets a non-unique index on the column in the underlying database)
fkcolumn Optional  

If the property is a related entity, you may specify the attribute of the entity to store in this field. This is useful when creating relationships to Mura's entities. For example:

property name="site" 
         cfc="site" 
         fieldtype="many-to-one" 
         fkcolumn="siteid";
html Optional false

This property is parsed only if stricthtml=true in the settings.ini.cfm file. 

If true, Mura will allow HTML in the string to be saved. If false, Mura will return an error if the string contains HTML when being saved.

length Optional 50 If the datatype attribute is set to "varchar" or "char", you may specify the maximum number of characters to allow.
loadkey Optional   If the property is a related entity, you may specify the attribute of the entity to load by.
message Optional   If required, or fails validation, the error message to return to the user.
relatesto Optional   Alias for "cfc"
name Required   Name of the property.
nullable Optional false If true, empty values will be stored as NULL.
orderby Optional   If property is a related entity, you may specify the related entity's property you wish to sort by.
persistent Optional true If false, a column in the related table will not be created for the property.
required Optional false If true, an error will be sent to the user if a value is not set.
singluarname Optional  

If the property is a related entity, this allows you to use a singular name in lieu of the property name itself. For example:

property name="addresses" 
         singularname="address" 
         cfc="address" 
         fieldtype="one-to-many";
validate Optional  

If you desire the entity to be validated before saving, you may use one of the following options:

  • date
  • datetime
  • numeric
  • email
  • regex
  • url

Validation Attributes

If property has a "validate" attribute, you may include additional attributes to the property for validation.

Attribute Description
regex The regular expression to use for validation.
minvalue The minimum value to allow.
maxvalue The maximum value to allow.
minlength The minimum length to allow.
maxlenth The maximum length to allow.
inlist The list to compare against.
method A custom entity method to execute.
lte Less than or equal to.
lt Less than.
gte Greater than or equal to.
gt Greater than.
eq Equal to.
neq Not equal to.

The example below illustrates how to use a validation attribute, when a property has a "validate" attribute.

property name="year" datatype="int" validate="numeric" minvalue="1900" maxvalue="2017";

Related Entity Synthesized Methods

If the property is a related entity, and the fieldtype attribute is either "one-to-many" or "many-to-many", the following methods are automatically available to the entity itself. The methods below are executed for both the property's name and singularname.

Method Description
get{PropertyName}Iterator Returns an iterator of related entities. For example: entity.getAddressesIterator()
get{PropertyName} Under the hood, returns get{PropertyName}Iterator.
get{PropertyName}Query Returns a recordset/query of the related entities. For example: entity.getAddressesQuery()
has{PropertyName} Returns a recordcount of related entities. Useful for if/else statements.
add{PropertyName} Pass in the object/entity to save as a related entity, and Mura will automatically save the related entity when executing the call to entity.save(). Useful for adding multiple related entities. For example: entity.addPhoneNumber(phoneNumberObject)
remove{PropertyName} Pass in the object/entity to be deleted, and Mura will automatically delete the related entity when executing the call to entity.save(). For example: entity.removePhoneNumber(phoneNumberObject)

If the property is a related entity, and the fieldtype attribute is either "one-to-one" or "many-to-one", the following methods are automatically available to the entity itself.

Method Description
get{PropertyName} Returns the related entity. For example: entity.getEmergencyContact()
add{PropertyName} Pass in the object/entity to save as a related entity, and Mura will automatically save the related entity when executing the call to entity.save(). For example: entity.addEmergencyContact(emergencyContactObject)
remove{PropertyName} Pass in the object/entity to be deleted, and Mura will automatically delete the related entity when executing the call to entity.save(). For example: entity.removeEmergencyContact(emergencyContactObject)

Example Mura ORM Component With Properties

The following code defines an entity named "something" that contains a few basic properties.

component 
  extends="mura.bean.beanORM"
  entityname="something"
  table="somethings"
  bundleable="true"
  displayname="SomethingBean"
  public=true
  orderby="namefirst,namelast" {

  // primary key
    property name="somethingid" fieldtype="id";

  // attributes
    property name="namefirst" datatype="varchar" length="255" required=true;
    property name="namelast" datatype="varchar" length="255" required=true;

  // methods could go here
}

Working With Entities

The code examples below demonstrate various methods for working with entities. As you'll see, the syntax is no different than working with any other Mura bean object.

// Loading entities
entity = m.getBean('entityName')
          .loadBy(someAttribute='Something');

// Getting attributes
entity.get('attributeName');

// Setting attributes
entity.set('attributeName', 'Some Value')

// Deleting entities
entity.delete();

// Saving entities
entity.save();

// Get a feed of entites
m.getFeed('entityName');

Error Handling

As previously mentioned, working with entities is no different than working with any other Mura bean object. We've already covered a bit of error handling, but it doesn't hurt to review it once again here.

Errors are returned as a structure, where each key in the struct represents the object's attribute "name", and the value contains the error message itself.

entity.save();

// If the bean has errors, then it did not save...
if ( entity.hasErrors() ) {

  // errors are returned as a struct
  errors = entity.getErrors();

  WriteOutput('<h3>Please review the following errors:</h3><ul>');

  // Loop over the errors
  for ( e in errors ) {
    WriteOutput('<li>Attribute: #e# <br> Message: #errors[e]#</li>');
  }

  WriteOutput('</ul>');
} else {
  WriteOutput('<h2>Success :: No Errors!</h2>');
}

Custom Validation

Mura also allows you to include your own custom validation rules. In order to do so, you simply include a custom validate() method in your entity's component file (.CFC), and when a save() call is made on your entity, it will trigger your custom method. The key is you don't "return" anything, you simply add your custom errors to the existing errors struct.

You could also use this to do complex validation requirements. For example, maybe you have a custom radio button or checkbox, and when it's selected, your form displays additional form fields that you will then want to be "required". You could simply check for the existence and/or value of the triggering field, and if it exists, run through each of the additional required form fields in your own validation.

The example below demonstrates how to create your own error messages when validating an attribute of your entity.

public any function validate() {

  // This runs the standard validation ... 
  // which will use your property definition's "validate" requirements, etc.
  // and it also gives you a way to reference the entity object itself
  var obj = super.validate();

  // Obtain a reference to any errors
  var errors = obj.getErrors();

  // Now, you can check anything you want on your properties or entity attributes
  // For example, if you have a property labeled "wantsmoreoptions" and it's true,
  // You could check for the other fields
  if ( obj.get('wantsmoreoptions') ) {

    // Yes, they want more options!
    // Make sure they completed them ...
    if ( !Len(obj.get('option99')) ) {
      errors.option99 = 'Option 99 is required.';
    }    

    // etc. ...
  }

}

Example Mura ORM Entities

To have a more cohesive understanding of how to work with Mura ORM, let's describe a simple application, and the objects we'll need to create for it.

Let's assume our client has asked us to create an "Address Book" type of application. This application would require an authorized user to be able to add, edit/modify, and/or delete Address Book entries. Each authenticated user would have their own Address Book. In other words, if Suzie logged in, she would only be able to see, create and/or modify her own entries.

Again, we're going to try and refrain from overcomplicating things. However, as a developer, It's easy to begin anticipating all kinds of enhancements and/or modifications you may want to make, and that's great. For now though, let's just stick to the script.

Address Book

Since a typical address book is filled with people, we'll start off by creating a Person object. Next, we'll have to consider the kind of properties or attributes a Person object should have. For example, they could have a first name, last name, zero or more phone numbers (PhoneNumber objects), zero or more addresses (Address objects), and so on.

The address book entry (Person) would be treated as a single object. It could be referenced by a single variable containing a pointer to the object. In addition, various helper methods could be associated with the object, such as a method to return the preferred phone number, the home address, and so on.

The following illustration is a sample UML diagram of our objects.

So, using our very basic objects, we can now begin to create our Mura ORM entities.

Person

Using our previous example, we could start our Person.cfc with the following code.

component 
    extends="mura.bean.beanORM" 
    table="custom_persons" 
    entityname="person" 
    bundleable="true" 
    displayname="PersonBean" 
    public=true 
    orderby="namelast,namefirst" {

    // primary key
        property name="personid" fieldtype="id";

    // person attributes
        property 
            name="namefirst" 
            datatype="varchar" 
            length="255" 
            nullable=true;

        property 
            name="namelast" 
            datatype="varchar" 
            length="255" 
            nullable=true;

    // relationships
        property 
            name="phonenumbers" 
            singularname="phonenumber" 
            cfc="personphonenumber" 
            fieldtype="one-to-many" 
            loadkey="personid" 
            cascade="delete" 
            orderby="phonetype";

        property 
            name="addresses" 
            singularname="address" 
            cfc="personaddress" 
            fieldtype="one-to-many" 
            loadkey="personid" 
            cascade="delete" 
            orderby="addresstype";

    // Custom Methods
        public string function getFullName() {
            return get('namefirst') & ' ' & get('namelast');
        }

        public any function getHomeAddress() {
            var rs = QueryExecute(
                ('
                    SELECT addressid 
                    FROM custom_personaddresses 
                    WHERE addresstype = "Home" 
                        AND personid = :pid
                ')
                , { pid=get('personid') }
            );

            return rs.recordcount
                ? getBean('personaddress').loadBy(addressid=rs.addressid)
                : getBean('personaddress').set('adddresstype', 'Home');
        }

}

PersonPhoneNumber

The PersonPhoneNumber.cfc defines our PersonPhoneNumber entity.

component 
    extends="mura.bean.beanORM" 
    table="custom_personphonenumbers" 
    entityname="personphonenumber" 
    bundleable="true" 
    displayname="PersonPhoneNumberBean" 
    public=true {

    // primary key
        property name="phonenumberid" fieldtype="id";

    // foreign key
        property 
            name="person" 
            fieldtype="many-to-one" 
            cfc="person" 
            fkcolumn="personid" 
            nullable=true;

    // attributes
        property 
            name="phonetype" 
            datatype="varchar" 
            length="255" 
            nullable=true; // Home, Office, Mobile, etc.

        property 
            name="phonenumber" 
            datatype="varchar" 
            length="255" 
            nullable=true;
}

PersonAddress

The following code comprises our PersonAddress.cfc and will define our PersonAddress entity.

component 
    extends="mura.bean.beanORM" 
    table="custom_personaddresses" 
    entityname="personaddress" 
    bundleable="true" 
    displayname="PersonAddressBean" 
    public=true {

    // primary key
        property name="addressid" fieldtype="id";

    // foreign key
        property 
            name="person" 
            fieldtype="many-to-one" 
            cfc="person" 
            fkcolumn="personid" 
            nullable=true;

    // attributes
        property 
            name="addresstype" 
            datatype="varchar" 
            length="255" 
            nullable=true; // Home, Office, etc.

        property 
            name="street1" 
            datatype="varchar" 
            length="255" 
            nullable=true;

        property 
            name="street2" 
            datatype="varchar" 
            length="255" 
            nullable=true;

        property 
            name="city" 
            datatype="varchar" 
            length="255" 
            nullable=true;

        property 
            name="state" 
            datatype="varchar" 
            length="255" 
            nullable=true;

        property 
            name="zip" 
            datatype="varchar" 
            length="255" 
            nullable=true;
}

Example

The example below illustrates how to use the entities we've created to get an iterator of a person's phone numbers.

contactBean = m.getBean('person').loadBy(persionid=m.event('pid'));

// Phone Numbers Iterator
itPhones = contactBean.getPhoneNumbersIterator();

while ( itPhones.hasNext() ) {
  phone = itPhones.next();
  WriteOutput( phone.get('phonenumber') );
)

Mura ORM Feed

As covered in the Feed Bean section, Feed beans allow developers to programmatically query Mura for other beans/objects. These same conventions work for custom entities. That said, if you tested some of the code examples from the Example Mura ORM Entities section, you might have some Person objects created, and you could test some of the Feed bean methods out.

The example below simply demonstrates how simple it is to create a feed of a custom entity, using the same methods described from the Feed Bean section.

// Persons Feed, based on the currently logged in user's userid
feedPersons = m.getFeed('person')
              .where()
              .prop('userid')
              .isEQ(m.currentUser('userid'))
              .sort('namelast', 'asc')
              .sort('namefirst', 'desc');

// Persons Iterator
itPersons = feedPersons.getIterator();

Mura ORM Events

As covered in the Mura ORM Configuration section, any .CFC's discovered under a "../handlers/" directory within a "model" directory, will automatically be registered as custom event handlers. For example, ../model/handlers/myhandler.cfc.

In the Mura Events section, we learned the various events that are announced during the lifecycle of the application and each request. In addition to the events documented there, Mura also announces special events for basic "CRUD" activities such as when saving, updating, or deleting an entity. To leverage any of these events, you simply add your methods to your custom event handler(s).

Event Description
onBefore{EntityName}Save Announced before an entity is saved.
onAfter{EntityName}Save Announced after an entity is saved.
on{EntityName}Save Announced after an entity is saved.
onBefore{EntityName}Update Announced before an entity is updated.
onAfter{EntityName}Update Announced after an entity is updated.
onBefore{EntityName}Create Announced before an entity is created.
onAfter{EntityName}Create Announced after an entity is created.
onBefore{EntityName}Delete Announced before an entity is deleted.
onAfter{EntityName}Delete Announced after an entity is deleted.

The example below illustrates using one of the event handlers.

onBefore{Entity}Save(m) {
  // accessing the bean
  var bean = m.event('bean');

  // do something here
}

Supported ORM Entity Events

In addition to using an event handler, you could use an ORM Entity Event. The following table lists supported ORM Entity events. You could simply include any these methods in your entity's .CFC to provide custom logic where needed.

ORM Event Description
preLoad() This method is called before the load operation is complete or before the data is loaded from the database.
postLoad() This method is called after the load operation is complete.
preUpdate() This method is called before the update operation is complete.
postUpdate() This method is called after the update operation is complete.
preCreate() This method is called before the create operation is complete.
preInsert() This method is called before the insert operation is complete.
postCreate() This method is called after the create operation is complete.
postInsert() This method is called after the insert operation is complete.
preDelete() This method is called before the object is deleted.
postDelete() This method is called after the delete operation is complete.

Mura ORM Assembler & Scaffolder

Warning! This feature is in ALPHA status as of Mura v7.1, and functionality may change without notice.

The Mura ORM Assembler & Scaffolder is an extremely powerful user interface for creating, managing, and populating Mura ORM entities (objects).

Mura ORM Assembler

The Mura ORM Assembler enables for the creation and management of Mura ORM entity definitions and relationships. The Assembler creates and stores definitions of Mura ORM entities as JSON, which allows for the ability to export and import them between Mura instances. Mura.js also uses these JSON definitions and converts them into actual Mura ORM entities. The entities are automatically wired into Mura and are immediately available via Mura's JSON API as well as the Mura Scope via m.getBean('yourCustomEntityName'), and all of the other Mura ORM entity methods.

Mura ORM entities auto-created by the Assembler are located under the {context}/modules/dynamic_entities/model/beans/ directory as CFCs (ColdFusion Components).

Note: These Mura ORM entities are not update safe. Any changes you manually make directly to the entity definition itself will be overwritten, if you edit it again using the Assembler.

As you can imagine, creating entities with the Mura ORM Assembler is much easier and convenient than creating them by hand, saving developers a huge amount of time.

Mura ORM Scaffolder

The Mura ORM Scaffolder lets you create, read, update/edit, and delete Mura ORM entity data. Only entities specifically enabled for the Scaffolder (via a flag in the entity's component definition) may be managed using the Scaffolder. In addition, only users in assigned permission groups are able to manage these entities via the Mura ORM Scaffolder.

Using the Scaffolder not only saves developers time, but also saves them from having to create a custom user interface for managing entity data while leveraging Mura's baked-in permission functionality.

 

Enable/Disable Mura ORM Assembler & Scaffolder

Warning! This feature is in ALPHA status as of Mura v7.1, and functionality may change without notice.

To enable or disable the Mura ORM Assembler and Scaffolder, follow the steps below.

  1. From the back-end administration area of Mura, go to Site Settings > Edit Settings.
  2. Select the Modules tab.
  3. Set "Mura ORM Scaffolding (ALPHA)" to "On" to enable, or "Off" to disable.
  4. Then, click Save Settings to save your desired settings.

How to Use the Mura ORM Assembler

Warning! This feature is in ALPHA status as of Mura v7.1, and functionality may change without notice.

As previously mentioned, the Mura ORM Assembler enables for the creation and management of Mura ORM entity definitions and relationships. Once you've enabled the Mura ORM Assembler & Scaffolder, you may follow the steps outlined below to create Mura ORM entity definitions and relationships. Only Super Admin Users are able to use the Mura ORM Assembler.

  1. From the back-end administration area of Mura, select Content on the main navigation, then select the Custom tab.
  2. To create a new Mura ORM entity, click the Add button.
  3. You should be taken to the Custom Mura ORM Entity screen.
  4. Complete the information on the Definition tab. The primary fields are described below.
    • Entity Name
      • A variable-safe name (no spaces, begins with a letter, letters, numbers and underscores only). For instance, if you were creating a "Book" entity, you might call this entity simply "book".
    • Display Name
      • This is the human-readable version of the Entity Name, such as "Department Heads" or "Types of Pets".
    • Table Name
      • This is the table name the entity's data will be stored in. It is usually advisable to match it to the entity name, and is often prefixed with some special name to distinguish it in the database and avoid naming collisions with Mura's own table names. For instance, a "book" entity might have a table name like "custom_books" or "mycompany_books".
    • Order By (optional)
      • This is the default property (column) by which to sort/order your entity data by. It must match one of the Property Names of the entity (see below).
    • Scaffold
      • If enabled, this gives the entity permission to be managed in the Mura ORM Scaffolder for data entry/management.
    • Bundleable
      • If enabled, the entity and any stored data will be included in any site bundles.
    • Publicly Accessible
      • If enabled, the entity may be displayed and/or managed via the front-end of your Mura site. However, you will also be responsible for building the user interface for display and/or management on the front-end itself.
  5. Also on the Definition tab, is where you manage the Entity Properties and relationships. An entity's "properties" are the fields where data will be stored, and will essentially be turned into columns within the defined Table Name. Every entity has a mandatory "id" property, which you may rename, but not delete. In addition, new entities also begin with an optional "siteid" property, which is important for tying the data to a specific Mura site. An entity's "relationships" are the keys that bind your entity to other Mura ORM entities.
    • How to Add /Edit Properties
      • Click the Add Property button, or select a property to edit.
      • You should now see the Property Details screen. The fields are described below.
        • Property Name
          • The variable-safe name for the property. For example, "booktitle" or "bookauthor".
        • Display Name
          • The human readable version of the property name. For example "Book Title" or "Book Author".
        • Data Type
          • The SQL data type the property should be saved as.
          • Valid options are:
            • VarChar
            • Text
            • Int
            • Boolean
            • DateTime
            • Any
        • Field Type
          • Valid options are:
            • None
              • This is the default value, and if selected, no database index will be created.
            • Index
              • If selected, a database index will be created on the property.
        • Default
          • The value entered here will be used as the default value in the Mura ORM Scaffolder. This is useful when the property's Form Field type is set to Dropdown or Radio to pre-select one of the the option list values.
        • Form Field
          • The value selected here will determine how the form field will appear in the Mura ORM Scaffolder when administrators are entering data.
          • Valid options are:
            • Text Field
            • Text Area
            • HTML Editor
            • Dropdown
            • Checkbox
            • Radio
            • Hidden
            • Do not render
        • Length
          • The maximum length of the data field.
        • Required
          • If checked, the property will be required in the Mura ORM Scaffolder.
        • List
          • If checked, the property will be displayed in the list view of the Mura ORM Scaffolder.
        • Filter
          • If checked, end users may use the "Filter By" functionality on this property in the list view of the Mura ORM Scaffolder.
        • Nullable
          • If checked, the property will be set to "NULL" in the database if no value is entered in the Mura ORM Scaffolder.
        • Option List
          • This field will appear if the Form Field type is set to Dropdown or Radio. Enter a carat (^) delimited list of values to be used as the labels for the form field. For example, "Matt^Grant^Steve".
        • Option Value List
          • This field will appear if the Form Field type is set to Dropdown or Radio. Enter a carat (^) delimited list of values to be used as the value which will be stored in the database. For example, "001^002^003". 
      • When finished, click the Add Property button.
      • To reorder Entity Properties, click+drag and drop the properties.
      • Click Save when finished.
      • A message will appear at the top of your screen to indicate when the entity definition has been saved.
      • In addition, a ".CFC" file will be auto-generated and saved under {context}/modules/dynamic_entities/model/beans/{EntityName}.cfc. If you wish, you could copy this file and save it under your own ../model/beans/ directory, and then delete the auto-generated file itself.
      • If you wish to delete the entity, simply click the Delete button, and select OK on the Alert dialog window. Also, when deleting entities, only the entity definition itself will be deleted from Mura, and the auto-generated ".CFC" file. However, all data will still be stored in the associated tables.
    • How to Add/Edit Relationships
      • Click the Add Relationship button, or select a relationship to edit.
      • You should now see the Relationship Details screen. The fields are described below.
        • Property Name
          • The variable-safe name that references the related entity. For example, a "book" entity might have related "authors". So, you could enter "author" or "authorid".
        • Display Name
          • The label, or human readable version of the relationship. For example, "Author" or "Author ID".
        • Relationship Type
          • When working with relationships, read the relationship from left to right. In other words, the left word refers to the current entity, and the word on the right refers to the related entity.
          • Valid Options:
            • one-to-many
              • This common type of relationship indicates the current entity may be related to multiple related entities. For example, one "order" entity could be related to multiple "product" entities.
            • one-to-one
              • This very simple relationship indicates there will only be one related entity to the current entity. For example, each "product" entity can be related to only one "manufacturer" entity.
            • many-to-one
              • Similar to the one-to-many relationship, this common relationship type indicates there may be multiple current entities related to a single entity. For example multiple "product" entities can be related to only one "order" entity.
          • If you wish to create a "many-to-many" relationship, the recommended approach is to simply create a one-to-many/many-to-one association between three participating entities. In other words, you would create a special entity to bind the related entities together. For example, you could have an "author" entity, a "book" entity, and a "authorsbooks" entity which stores the primary key values of both "authors" and "books" as a "many-to-one" relationship. For more information on this approach, view our blog post titled Mura ORM and Many-to-Many Relationships.
        • Relates To
          • Select the actual entity that this entity is related to. Only defined entities will appear in the list, in addition to Mura's own entities (such as "content" and "user"). If the desired entity has not been defined yet, you will need to define the entity, and come back to create the relationship.
        • Foreign Key Column
          • In most cases, this should be the related entity's "Primary Key" field. However, there may be an occasion where another field should be used to bind the entities together.
        • Render Field
          • The select menu will be populated with the properties of the selected entity from the "Relates To" field. Select the desired property to display when viewing the entity list in the Mura ORM Scaffolder table. For example, if the related entity is "author", you may wish to select the "Last Name" property instead of some obscure "authorid" property.
        • Load Key
          • This field relates to the Foreign Key Column. If the current entity is related by something other than the Primary Key, you should enter it here.
        • Cascade Delete?
          • Valid Options:
            • none
              • Do nothing if any related entities are deleted.
            • delete
              • If selected, this entity will be deleted when the related entity is deleted.
      • When finished, click the Add Relationship button.
    • The relationship will now display under the Entity Properties area. Simply click the gears icon to edit the relationship again, if desired.
  6. The JSON tab displays the string to be saved in the database as the definition of the entity, and captures all of the properties and relationships created using the Mura ORM Assembler. This is especially useful information when using Mura.js to work with Mura ORM entities.
  7. When finished, click the Save button to save your entity definition.

     

How to Use the Mura ORM Scaffolder

Warning! This feature is in ALPHA status as of Mura v7.1, and functionality may change without notice.

As previously mentioned, the Mura ORM Scaffolder lets you create, read, update/edit, and delete Mura ORM entity data. Once you've enabled the Mura ORM Assembler & Scaffolder, you may follow the steps outlined below to manage your Mura ORM entity data, assuming Mura ORM entities enabled for use in the Scaffolder exist.

Also, by default, Super Admin Users, and members of the Admin group are automatically granted permissions to the Mura ORM Scaffolder. However, members of these groups may also enable other groups access by managing the permissions to this section.

  1. From the back-end administration area of Mura, select Content on the main navigation, then select the Custom tab.
  2. You should be able to view to the Custom Entities table. This landing page lists all entity types available for editing via the Scaffolder. For example, the list below includes "Author", "Book", and "BooksAuthors Relationships".
  3. To view an entities data entries, click the entity name on the list, or select the three-dot menu to the left of the entity name, and click the "List" option.
  4. You should be taken to the entity's listing of entries. For example, in the illustration below, you can see the "Author" entries.
  5. If a column (attribute) is filterable, there will be a text box above the column header. You may enter the search text and click the Enter/Return key or the Apply Filter button to filter the results.
  6. To remove the filter, click the Remove Filter button.
  7. You may also click on a column header to sort data on that column, and an arrow will appear by the header to indicate the sort direction.
  8. To edit a entity, click on an entity attribute, or select the three-dot menu to the left, and click Edit.
  9. You will then be taken to the entity's data entry screen.
  10. To save the entity after making your edits, click the Save button.
  11. To delete an entity, click the Delete button.
  12. To add a new entity, from the entity's listing of entities, click the Add button.
  13. You will be taken to the Edit screen. When creating or editing an entity, the form that appears will be determined by the entity's definition as created in the Mura ORM Assembler.
  14. Complete the form data, then click Save to save your new entity.
  15. Congratulations! You've successfully edited or added an entity.

Mura Iterators

According to Merriam-Websteriterate means "to say or do again or again and again." In programming, an "iterator" is a design pattern. An iterator wraps a collection or group of objects (e.g., queries/recordsets, arrays, lists, structs, beans, etc.) with common helper methods without the need to fully know or understand the underlying data structure. This allows programmers to use common methods for looping over, or iterating over, many different types of collections or groups of objects.

Mura Iterators are an array of objects, and have a number of common helper methods, allowing developers to loop/iterate over, collections/groups of objects. Mura Iterators wrap an underlying query, and use the returned recordset as the basis for its array of objects. This also means the order of objects in the iterator is determined by the sort order of the underlying recordset.

As you may have already seen in other sections of the documentation, Mura relies on the iterator design pattern itself. Many of Mura's common beans include helper methods which return some type of iterator. For example, in the Content Bean section, you'll see methods such as getRelatedContentIterator(), getCommentsIterator(), etc.

If you've worked with recordsets/queries in the past, you'll find iterators to be quite similar. However, working with iterators gives you so much more power than merely looping over a query/recordset. When iterating over a collection of Mura objects, you'll have access to the entire object itself, including its helper methods. However, if you were merely looping over a query/recordset using <cfoutput> tags, you would only have access to the fields included in the record itself. In addition, when working with a standard query/recordset, it can be cumbersome to do things like pagination, or even loop backwards without having to rewrite the underlying query itself. Mura Iterators can do all of these things for you, and so much more.

Iterator Basics

As an object itself, Mura Iterators have a number of attributes you can inspect using its helper methods. Iterators hold data pertinent to looping over collections or groups of objects. For example, Mura Iterators know how many objects there are in the collection it's working with. They also know if you've started to loop/iterate over the collection, what object you're currently working with, which "page" your on, and so on.

You can use these helper methods to ask the iterator for the next object, or even the previous object, and then do whatever you want with the object itself, and when finished, move on to the next object. For example, you could manipulate each object, and then re-save it. If the objects were content items, you could loop over each object, and then output the associated image and a title to create a slideshow. The possibilities are endless.

While Mura Iterators offer several helper methods, there are only two primary methods you need to know to begin working with them; hasNext() and next().

hasNext()

The hasNext() method inspects the underlying collection/array of objects, and then returns true if there are still objects in the array of objects you're working with, or false, if there are no more objects in the array to work with.

next()

The key method, next(), queues up the next object in the collection/array of objects, and gives you a way to reference the current item/object so you can work with it.

Basic Examples

The examples below demonstrate using the basic hasNext() and next() methods.

Tag-based Example

<cfloop condition="iterator.hasNext()">
  <cfset item = iterator.next()>
  <!--- Do something with 'item' --->
  <cfdump var="#item#">
</cfloop>

Script Example

while ( iterator.hasNext() ) {
  item = iterator.next();
  // Do something with 'item'
  WriteDump( item );
}

// OR

do {
  item = iterator.next();
  // Do something with 'item'
} while ( iterator.hasNext() );

Conditionals

You could also wrap the prior examples with a conditional, and return something in the event that the iterator is empty.

if ( iterator.hasNext() ) {
  // Iterator has objects
} else {
  // Iterator is empty ... no objects
}

 

Key Iterator Methods

The key Mura Iterator methods are described below.

Method Returns Description
hasNext boolean Returns true if iterator has objects in the array, and hasn't finished looping. Returns false, if iterator is empty, or has finished looping. This method "looks right" or forward, in the array of objects.
next object Moves the "index" to the next object, or next record in the underlying query's recordset. Returns the next object in the iterator (array of objects). Usually assigned to a variable, in order to have a way to reference the current object being looped over in the array of objects.
peek object Returns the object after the current object being looped over (or next) in the iterator. It's a way to "peek" at what's up next.
reset n/a Resets the "index" back to the beginning. Useful for when you need to loop over an iterator more than once.
end n/a Moves the "index" to the last object, or last record in the underlying query's recordset.
hasPrevious boolean Similar to hasNext, except it "looks left" or backward, in the array of objects. Returns true if iterator has an object that it has previously looped over, or false, if the index is at the beginning.
previous object Moves the "index" to the previous object, or previous record in the underlying query's recordset. Usually assigned to a variable, in order to have a way to reference the current object being looped over in the array of objects.
setQuery n/a Expects a query parameter, and an optional maxRecordsPerPage (defaults to 1000) parameter, to set the underlying query used for the iterator.
getQuery query Returns the underlying query used for the iterator.
getRecordCount numeric Returns the total number of records in the underlying query used for the iterator.
setPage n/a Expects a pageIndex parameter, to set the page of records/objects the iterator should be working with.
getPage numeric Returns the page index of records/objects the iterator is currently working with.
pageCount numeric Returns the total number of pages the iterator has, based on the total number of items/records and number returned from getItemsPerPage().
setItemsPerPage n/a Expects a itemsPerPage parameter, to set how many items per page the iterator should be working with. Formerly known as setNextN().
getItemsPerPage numeric Returns the number of items per page the iterator is currently working with. Formerly known as getNextN().
setStartRow n/a Expects a startRow parameter, to set which row of the underlying query the iterator should be working with.
getStartRow numeric Returns the row of the underlying query the iterator is currently working with.
getCurrentIndex numeric Returns the index of the iterator is currently working with.

Examples

In addition to the examples listed below, be sure to view the examples in the Common Beans section, where many of Mura's objects include their own iterator methods.

Feed Bean Iterator

The example below demonstrates how to use a Feed Bean, and use its getIterator() method.

<cfset feedBean = m.getFeed('content').where().prop('credits').containsValue('Steve')>
<cfset it = feedBean.getIterator()>

<cfif it.hasNext()>
  <cfloop condition="it.hasNext()">
    <cfset item = it.next()>
    <div>
      <a href="#item.get('url')#">
        #esapiEncode('html', item.get('title'))#
      </a>
    </div>
  </cfloop>
<cfelse>
  <p class="alert alert-info">
    This iterator doesn't have any items.
  </p>
</cfif>

Content Iterator

You can use any query to populate and use Mura's contentIterator bean, as long as the query contains a siteid and contentid column.

rs = QueryExecute("
  SELECT contentid, siteid
  FROM tcontent
  WHERE active = 1
");

Now, use the contentIterator bean's setQuery method, and use the iterator.

it = m.getBean('contentIterator').setQuery(rs);

if ( it.hasNext() ) {
  item = it.next();
  // Do something with the item
  WriteDump( item.getAllValues() );
} else {
  // No items/records exist
}

Query Iterator

The example below demonstrates how to use a regular query with Mura's queryIterator bean.

rs = QueryExecute("
  SELECT *
  FROM someTable
");

Now, use the queryIterator bean's setQuery method, and use the iterator.

it = m.getBean('queryIterator').setQuery(rs);

if ( it.hasNext() ) {
  item = it.next();
  // Do something with the item
  WriteDump( item );
} else {
  // No items/records exist
} 

Summary

Mura's beans and objects are an integral part of Mura development. Throughout this section, we've covered everything from the basic syntax of working with Mura bean objects, what the most common bean objects are, and how the Mura Scope objects are merely wrappers of common beans. Additionally, we've covered creating and managing custom objects including custom Class Extensions, and Mura ORM. Finally, we learned about Mura Iterators, why they're important, and how to use them in our development.