mura orm & ember js
DESCRIPTION
Originally presented by Matt Levine at MuraCon EU 2014 in Edinburgh, Scotland.TRANSCRIPT
Mura ORM and EmberJS• By Matt Levine
Who Am I?
Who Am I?• CTO of Blue River Interactive Group
Who Am I?• CTO of Blue River Interactive Group• Started Mura CMS with Sean Schoeder a long time
ago...
What We’re Talking About
What We’re Talking About• Mura ORM
What We’re Talking About• Mura ORM• EmberJS
What We’re Talking About• Mura ORM• EmberJS• But Mostly Mura ORM
Why Mura ORM?
Why Mura ORM?• It all started with creating the Mura approval chains.
Why Mura ORM?• It all started with creating the new Mura approval
chains.• Needed to create 5 new entities and didn’t want to
write a custom DAO for each one.
Started with 3 Options
Started with 3 Options• Custom DAOs
Custom DAOs• Too much work
Custom DAOs• Too much work• No code re-use
Started with 3 Options• Custom DAOs• Mura Class Extension Module
Mura Class Extension ModuleGREAT FOR:
• Targeting nodes for custom business logic
Mura Class Extension ModuleGREAT FOR:
• Targeting nodes for custom business logic• Rendering events
Mura Class Extension ModuleGREAT FOR:
• Targeting nodes for custom business logic• Rendering events• Data events
Mura Class Extension ModuleGREAT FOR:
• Targeting nodes for custom business logic• Rendering events• Data events• Adding custom values to be used within rendering and
data events
Mura Class Extension ModuleNOT AS GOOD FOR:
• Maintaining relationships between entities
Mura Class Extension ModuleNOT AS GOOD FOR:
• Maintaining relationships between entities• Really custom business logic
Mura Class Extension ModuleNOT AS GOOD FOR:
• Maintaining relationships between entities• Really custom business logic• Directly querying the database
Mura Class Extension ModuleRECAP:
• Only handles very simple entities
Mura Class Extension ModuleRECAP:
• Only handles very simple entities• Great for hooking attributes to existing Mura entities, but
bad for complicated logic.
Mura Class Extension ModuleRECAP:
• Only handles very simple entities• Great for hooking attributes to existing Mura entities, but
bad for complicated logic.• Want the data to be stored in flat tables.
Mura Class Extension ModuleRECAP:
• Only handles very simple entities• Great for hooking attributes to existing Mura entities, but
bad for complicated logic.• Want the data to be stored in flat tables.• Not the appropriate choice
Started with 3 Options• Custom DAOs• Mura Class Extension Module• CF based Hibernate ORM
CF Hibernate ORMGREAT FOR:•Easily defining entity properties
CF Hibernate ORMGREAT FOR:•Easily defining entity properties•CRUD operations
CF Hibernate ORMGREAT FOR:•Easily defining entity properties•CRUD operations•Managing relationships to other CF ORM entities
CF Hibernate ORMGREAT FOR:•Easily defining entity properties•CRUD operations•Managing relationships to other CF ORM entities•You just describe the entity with properties and start
using it!
CF Hibernate ORMNOT SO GOOD FOR:•Creating relationships to Mura core entites
CF Hibernate ORMNOT SO GOOD FOR:•Creating relationships to Mura core entites•Working with DI1
CF Hibernate ORMNOT SO GOOD FOR:•Creating relationships to Mura core entites•Working with DI1•Don’t want to deal with sharing hibernate sessions with
other application and plugins
CF Hibernate ORMNOT SO GOOD FOR:•Creating relationships to Mura core entites•Working with DI1•Don’t want to deal with sharing hibernate sessions with
other application and plugins• It just works, but when it doesn't... Good Luck
CF Hibernate ORMRECAP:•Love the concept!
CF Hibernate ORMRECAP:•Love the concept!•Seems like CF ORM would be a walled garden.
CF Hibernate ORMRECAP:•Love the concept!•Seems like CF ORM would be a walled garden.•Sharing a ORM session with other sub applications
sounds like a nightmare
CF Hibernate ORMRECAP:•Love the concept!•Seems like CF ORM would be a walled garden.•Sharing a ORM session with other sub applications
sounds like a nightmare• I would like the relationships to be based on DI1
BeanName or Alias rather than component path.
CF Hibernate ORMRECAP:•When things go wrong it really feels like a black box. You
get low level java error that don't neccesarilly easily map to what you did wrong in your CFML•CF ORM really seems to want you to forget about sql
and just go through it's black box. I like sql. I think is it's pretty darn cool
What if?
What if?• I roll my own that works exactly how Mura works!
I Could Make Them Accesible via $.getBean(entityName); and application.serviceFactory(entityName);Takes advantage of DI1 dependency injection
Have the Same Interactions• entity.loadBy()• entity.get{relateEntity}Iterator();• entity.get{relateEntity}Query();• entity.get{relateEntity}();• entity.getFeed();• entity.validate();• entity.getError();
Have the Same Interactions• entityFeed.addParam();• entityFeed.getQuery();• entityFeed.getIterator();
Have the Same Interactionsfeed=$.getBean(entityName).getFeed();feed.addParam(column=’mycolumn’,criteria=‘test’);iterator=feed.getIterator();!
<cfloop condition=”iterator.hasNext()”><cfoutput>#iterator.next().getMyColumn()#</cfoutput></cfloop>
Be Targetable By Mura Eventscomponent extends=”mura.cfobject”{
onBeforeMyEntitySave($){var bean=$.event(‘bean’);....
}}
They Could Also• Know how to bundle themselves• Play well with Mura content versioning• Have a more simple implementation than CF ORM
It could use the same component attributes
• entityName• table• datasource• discriminatorColumn• discriminatorValue
• orderby• readonly
With some new ones• bundleable• cacheName• dbtype• manageSchema• useTrash
It could use the same property attributes
• name• persistent• fieldtype• cfc• fkcolumn
• type• cascade• singularName• orderby• length
• default• ormType
!
!
With some new ones• dataType• nullable• required• validate• message
• regex• comparable
And a bunch attributes for validation
• minValue• maxValue• minLength• maxLength• minCollection
• maxCollection• minList• maxList• inList• method
• lte• lt• gte• gt• eq
• neq
It could also support CF ORM • preLoad();• postLoad();• preUpdate();• postUpdate();• preCreate();
• postCreate();• postInsert();• preDelete();• postDelete();
So that’s what we did
So that’s what we did• Now let’s actually see some code
EmberJS
EmberJS• A Framework for Creating Ambitious Web Applications
EmberJS• A Framework for Creating Ambitious Web Applications• A Client Side MVC Framework
EmberJS• A Framework for Creating Ambitious Web Applications• A Client Side MVC Framework• That’s opinionated in a good way
EmberJS• A Framework for Creating Ambitious Web Applications• A Client Side MVC Framework• That’s opinionated in a good way• So that your application is developed in a consistent
way which enables easier scalability
EmberJS• A Framework for Creating Ambitious Web Applications• A Client Side MVC Framework• That’s opinionated in a good way• So that your application is developed in a consistent
way which enables easier scalability• Utilizes Handlebars.js for easy templating
Handlebar.JS<div> <label>Name:</label> {{input type="text" value=name placeholder="Enter your name"}}</div><div class="text"><h1>My name is {{name}} and I want to learn Ember!</h1></div>
Ember-Data•A Data Persistence Library for Ember.js
Ember-Data•A Data Persistence Library for Ember.js•We’ve created a Mura ORM Adapter for Ember-Data
Ember-Data•A Data Persistence Library for Ember.js•We’ve created a Mura ORM Adapter for Ember-Data•Sooo…
Ember-Datacomponent extends="mura.bean.beanORM" entityName="widget" table="widgets" {property name="widgetid" fieldtype=“id";property name="name" type=“string"length="100" required=true message="The name attribute is required an must be.";
property name="options" singularname="option" fieldtype="one-to-many" cfc="option" cascade="delete"; }
Ember-DataApp.Widget = DS.Model.extend({ primaryKey: 'widgetid', widgetid: DS.attr(), siteid: DS.attr(), name: DS.attr(), options: DS.hasMany('Option',{async:true})});
Ember-Datacomponent extends="mura.bean.beanORM" entityName="option" table="widgetoptions" {property name="optionid" fieldtype="id";property name="name" type="string" length="100" required=true message="The name attribute is required an must be.";property name="widget" fieldtype="many-to-one" cfc="widget" fkcolumn="widgetid";}
Ember-DataApp.Option = DS.Model.extend({ primaryKey: 'optionid', optionid: DS.attr(), siteid: DS.attr(), name: DS.attr(), widgetid: DS.attr(), widget: DS.belongsTo('Widget',{async:true})});
Ember-DataApp.WidgetRoute = Ember.Route.extend({ model: function(params) { return this.store.find(‘Widget’,params.widgetid); }});
Ember-Data<script type="text/x-handlebars" id=“widget"><h3>{{name}} ({{options.length}})</h3>{{#if options.length}}<ul>{{#each option in options}} <li>{{option.name}}</li>{{/each}}</ul>{{/if}}</script>
Ember.js•We’re currently prototyping an Ember.js based front for Mura
Ember.js•We’re currently prototyping an Ember.js based front for Mura•It will allow Mura to run as a service
Ember.js•We’re currently prototyping an Ember.js based front for Mura•It will allow Mura to run as a service•This will allow Mura sites to be served locally on any web server without needing a servlet container.
Ember.js•We’re currently prototyping an Ember.js based front for Mura•It will allow Mura to run as a service•This will allow Mura sites to be served locally on any web server without needing a servlet container.•We feel at this point it’s a perfect fit