Hi there Nolan,
This might get you started in the right direction. While at
cfObjective (ANZ) last year I played around with CF/MongoDB and you're
right the serialise/deserialise bits are where you miss ORM.
Anyway - this has never been in production so you might need to
benchmark it and I got some/most of the code from one of the populate
projects somewhere (ha! well I was coding it up during
presentations :D)
It's pretty raw, but follows (roughly) the BaseOrmService,
VirtualEntityService used in Coldbox ORM
Happy for you to use this however you like. Not sure if it'll support
nested objects/models.
Cheers
Steve
BaseModelObject ------------------------------
component output="false"
{
public Struct function asStruct()
{
return deserializeJSON(serializeJSON(this));
}
public any function populate( required any data, any propList =
arrayNew(1))
{
var metadata = getMetadata(this);
param name="metadata.cleanseInput" default="false";
for(var i=1; i<=arrayLen(metadata.properties); i++)
{
if(not arraylen(arguments.propList) OR
arrayContains(arguments.propList,metadata.properties[i].name))
{
if(NOT StructKeyExists(metadata.properties[i],"fieldType") OR
metadata.properties[i].fieldType EQ "column")
{
if(StructKeyExists(arguments.data,metadata.properties[i].name))
{
/*The property has a matching argument*/
local.varValue = arguments.data[metadata.properties[i].name];
//For nullable fields that are blank, set them to null
if((NOT StructKeyExists(metadata.properties[i],"notNull") OR NOT
metadata.properties[i].notNull) AND NOT Len(local.varValue))
{
_setPropertyNull(metadata.properties[i].name);
}
else
{
//Cleanse input?
param name="metadata.properties[i].cleanseInput"
default="#metadata.cleanseInput#";
if(metadata.properties[i].cleanseInput)
{
local.varValue = _cleanse(local.varValue);
}
_setProperty(metadata.properties[i].name,local.varValue);
}
}
}
else if(metadata.properties[i].type EQ "array")
{
if(isDefined("arguments.data.#metadata.properties[i].name#"))
{
var entityName = metadata.properties[i].cfc;
var items =
evaluate("arguments.data.#metadata.properties[i].name#");
writeDump(var=items,label="in populate");
var entityArray = arrayNew(1);
for(var j=1; j<=arrayLen(items); j++)
{
var entity = createObject("component",entityName);
entity.populate(items[j]);
arrayAppend(entityArray,entity);
}
_setProperty(metadata.properties[i].name,entityArray);
}
}
//do many-to-one
else if(metadata.properties[i].fieldType EQ "many-to-one")
{
if(StructKeyExists(arguments.data,metadata.properties[i].fkcolumn))
{
local.fkValue = arguments.data[metadata.properties[i].fkcolumn];
}
else
if(StructKeyExists(arguments.data,metadata.properties[i].name))
{
local.fkValue = arguments.data[metadata.properties[i].name];
}
if(StructKeyExists(local,"fkValue"))
{
local.varValue =
EntityLoadByPK(metadata.properties[i].name,local.fkValue);
if(IsNull(local.varValue))
{
if(NOT StructKeyExists(metadata.properties[i],"notNull") OR NOT
metadata.properties[i].notNull)
{
_setPropertyNull(metadata.properties[i].name);
}
else
{
throw(detail="Trying to load a null into the
#metadata.properties[i].name#, but it doesn't accept nulls.");
}
}
else
{
_setProperty(metadata.properties[i].name,local.varValue);
}
}
}
}
}
}
function _cleanse (required any data)
{
return HTMLEditFormat(arguments.data);
}
private void function _setProperty (required any name, any value)
{
var theMethod = this["set" & arguments.name];
if(IsNull(arguments.value))
{
theMethod(javacast('NULL', ''));
}
else
{
theMethod(arguments.value);
}
}
private void function _setPropertyNull(required any name)
{
_setProperty(arguments.name);
}
}
end BaseModelObject---------------------------
User -----------------------------------------
component output="false" accessors="true" extends="BaseModelObject"
{
property name="id" type="any";
property name="firstname" type="String";
property name="lastname" type="string";
property name="email" type="string";
property name="username" type="string";
property name="password" type="string";
property name="testStruct" type="Struct";
property name="siteID" type="numeric";
property name="memberships" singularname="membership" type="array"
cfc="BaseMembership";
public User function init()
{
setSiteId(application.siteID);
return this;
}
}
end User -------------------------------------
BaseService ----------------------------------
component output="false" accessors="true"
{
property name="entityName" type="String" required="true" ;
property name="collectionName" type="String" required="true" ;
BaseService function init()
{
javaloaderFactory =
createObject('component','cfmongodb.core.JavaloaderFactory').init();
mongoConfig =
createObject('component','cfmongodb.core.MongoConfig').init(dbName="mongorocks",
mongoFactory=javaloaderFactory);
mongo =
createObject('component','cfmongodb.core.Mongo').init(mongoConfig);
if(isDefined("arguments.clearCollection") &&
isDefined("arguments.collectionName"))
{
if(arguments.clearCollection)
{
var collection = mongo.getDBCollection(arguments.collectionName);
collection.remove({});
}
}
if(isDefined("arguments.entityName") && len(arguments.entityName))
{
setEntityName(arguments.entityName);
}
return this;
}
private Struct function asStruct(any entity)
{
return deserializeJSON(serializeJSON(arguments.entity));
}
any function new(string entityName,struct properties=structnew())
{
var entity = createObject("component", arguments.entityName);
var key = "";
var excludes = "entityName,properties";
// Properties exists?
if( NOT structIsEmpty(arguments.properties) ){
entity.populate(arguments.properties );
}
//else{
//
populate(target=entity,memento=arguments,exclude="entityName,properties");
//}
return entity;
}
any function get(required string entityName,required any id)
{
collection = mongo.getDBCollection( getCollectionName() );
// Check if ID=0 or empty to do convenience new entity
if( isSimpleValue(arguments.id) and ( arguments.id eq 0 OR
len(arguments.id) eq 0 ) ){
return new(arguments.entityName);
}
// check if id exists so entityLoad does not throw error
if( (isSimpleValue(arguments.id) and len(arguments.id)) OR NOT
isSimpleValue(arguments.id) ){
var entityStruct = collection.findById(arguments.id);
writeDump(var=entityStruct, label="entity struct in base service");
// Check if not null, then return it
if( NOT isNull(entityStruct) ){
var entity = createObject("component",arguments.entityName);
entity.populate(entityStruct);
entity.setId(entityStruct._id.toString());
return entity;
}
}
}
any function save(any entity)
{
var entityAsStruct = asStruct(arguments.entity);
collection = mongo.getDBCollection( getCollectionName() );
collection.save(entityAsStruct);
entity.populate(entityAsStruct);
entity.setId(entityAsStruct._id.toString());
return entity;
}
}
end BaseService-------------------------------
VirtualObjectService -------------------------
component extends="BaseService" output="false" accessors="true"
{
property name="entityName" type="String" required="true" ;
property name="collectionName" type="String" required="true" ;
VirtualObjectService function init(required String entityName,
required String collectionName, boolean clearCollection=false)
{
super.init(argumentCollection=arguments);
// Set the local entity to be used in this virtual entity service
setEntityName(arguments.entityName);
setCollectionName(arguments.collectionName);
return this;
}
any function new(){
arguments.entityName = this.getEntityName();
return super.new(argumentCollection=arguments);
}
any function get(required any id){
arguments.entityName = this.getEntityName();
return super.get(argumentCollection=arguments);
}
}
end VirtualObjectService ---------------------
UserService ----------------------------------
component extends="VirtualObjectService" output="false"
{
public UserService function init(String collectionName="users",
boolean clearCollection=false)
{
super.init(entityName="User",collectionName=arguments.collectionName,
clearCollection=arguments.clearCollection);
return this;
}
}
end UserService ------------------------------