Mura Beans & Objects
The term "bean" is borrowed from the Java programming language. According to Wikipedia, JavaBeans are reusable software components. They are used to encapsulate many objects into a single object (the bean), so that they can be passed around as a single bean object instead of multiple individual objects.
In CFML, a bean can be a ColdFusion Component (CFC). However, there are a few characteristics the CFC must have to differentiate itself from other types of CFCs:
- Serializable
- A no-argument constructor
- Allows access to properties using getter and setter methods
In short, beans hold information about the object or entity they represent, and allow developers the ability to quickly and easily access and manipulate some of its attributes. For example, a bean could represent a person, and its attributes might contain data such as the person's name, age, height, weight, birthdate, etc.
Mura Bean Objects
In Mura, developers can use its software components without necessarily having to understand their inner workings. Mura bean objects provide developers the ability to directly access and manipulate their associated records in the database. This is most easily accomplished using the bean's associated helper methods. As you'll see in the Mura ORM section, developers may also create their own bean objects too.
Syntax
Here we cover the basic syntax that applies to all Mura bean objects. When you want to work with a specific bean object, you will first want to load it by a specific attribute. However, as each bean object is slightly different, the attributes you may load by will vary.
Loading Bean Objects
As illustrated in the examples below, you should use the special Mura scope (m
) method labeled getBean
, when you wish to work with a Mura bean object.
someBean = m.getBean('someBean') .loadBy(someAttribute='someAttributeValue');
You may optionally include a siteid
parameter to load a bean from another Mura site, managed under the same installation.
someBean = m.getBean('someBean') .loadBy(someAttribute='someAttributeValue', siteid='SomeSiteID');
Getting an Attribute of a Bean Object
The "getter" examples below illustrate how to "get" a specific attribute of a bean object.
someBean.get('attributeName'); someBean.get{AttributeName}(); someBean.getValue('attributeName');
Setting an Attribute of a Bean Object
The "setter" examples below illustrate how to "set" a specific attribute of a bean object.
someBean.set('attributeName', 'Some Value'); someBean.set{AttributeName}('Some Value'); someBean.setValue('attributeName', 'Some Value');
Verify Existence of a Bean Object
Most bean objects have a couple of helper methods to verify whether the bean object exists, or if it's new. Whichever method you choose, is entirely personal preference.
// returns `true` if bean exists, or `false` if it does not someBean.exists(); // returns `true` if bean is new, or `false` if bean already exists someBean.getIsNew();
Deleting Bean Objects
The basics for deleting a bean object is to simply call the delete
helper method. The following example assume you have a properly loaded bean to delete.
someBean.delete();
Creating, Updating, & Saving Bean Objects
The basics for saving a bean object is to simply call the save
helper method. The following example assumes you have a properly loaded bean to save, and may have made some changes to one or more attributes using one of the setter methods above.
someBean.save();
Error Handling
When saving an entity, if an error occurs, you'll need to figure out how you want to deal with the error(s). Keep in mind, if an error is returned, the save did not occur!
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.
someBean.save(); // If the bean has errors, then it did not save... if ( someBean.hasErrors() ) { // errors are returned as a struct errors = someBean.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>'); }
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 |
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. |
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. |
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 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. Valid
|
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>
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
|
|
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:
|
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 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:
|
|
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 If |
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:
|
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
Note: this feature is considered Beta status 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
To enable or disable the Mura ORM Assembler and Scaffolder, follow the steps below.- From the back-end administration area of Mura, go to Site Settings > Edit Settings
- Select the Modules tab
- Set "Mura ORM Scaffolding (ALPHA)" to "On" to enable, or "Off" to disable
- Then, click Save Settings to save your desired settings.
How to Use the Mura ORM Assembler
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.
- From the back-end administration area of Mura, select Content on the main navigation, then select the Custom tab.
- To create a new Mura ORM entity, click the Add button.
- You should be taken to the Custom Mura ORM Entity screen.
- 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
".
- 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 "
- 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.
- Entity Name
- 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
".
- The variable-safe name for the property. For example, "
- 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.
- None
- Valid options are:
- 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
".
- 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, "
- 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
".
- 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, "
- Property Name
- 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.
- This common type of relationship indicates the current entity may be related to multiple related entities. For example, one "
- 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.
- This very simple relationship indicates there will only be one related entity to the current entity. For example, each "
- 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.
- 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 "
- one-to-many
- 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.
- 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 "
- 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.
- none
- Valid Options:
- Property Name
- 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.
- How to Add /Edit Properties
- 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.
- When finished, click the Save button to save your entity definition.
How to Use the Mura ORM Scaffolder
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.
- From the back-end administration area of Mura, select Content on the main navigation, then select the Custom tab.
- 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".
- 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.
- You should be taken to the entity's listing of entries. For example, in the illustration below, you can see the "Author" entries.
- 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.
- To remove the filter, click the Remove Filter button.
- 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.
- To edit a entity, click on an entity attribute, or select the three-dot menu to the left, and click Edit.
- You will then be taken to the entity's data entry screen.
- To save the entity after making your edits, click the Save button.
- To delete an entity, click the Delete button.
- To add a new entity, from the entity's listing of entities, click the Add button.
- 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.
- Complete the form data, then click Save to save your new entity.
- Congratulations! You've successfully edited or added an entity.
Mura Iterators
According to Merriam-Webster, iterate 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.