PageRenderTime 448ms CodeModel.GetById 373ms app.highlight 4ms RepoModel.GetById 67ms app.codeStats 0ms

/wheels/model/callbacks.cfm

http://cfwheels.googlecode.com/
ColdFusion | 367 lines | 332 code | 17 blank | 18 comment | 49 complexity | a8b33e9102fdcbec57ae540a72a5c639 MD5 | raw file
  1<!--- PUBLIC MODEL INITIALIZATION METHODS --->
  2
  3<cffunction name="afterNew" returntype="void" access="public" output="false" hint="Registers method(s) that should be called after a new object has been initialized (which is usually done with the @new method)."
  4	examples=
  5	'
  6		<!--- Instruct Wheels to call the `fixObj` method --->
  7		<cfset afterNew("fixObj")>
  8	'
  9	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
 10	<cfargument name="methods" type="string" required="false" default="" hint="Method name or list of method names that should be called when this callback event occurs in an object's life cycle (can also be called with the `method` argument).">
 11	<cfset $registerCallback(type="afterNew", argumentCollection=arguments)>
 12</cffunction>
 13
 14<cffunction name="afterFind" returntype="void" access="public" output="false" hint="Registers method(s) that should be called after an existing object has been initialized (which is usually done with the @findByKey or @findOne method)."
 15	examples=
 16	'
 17		<!--- Instruct Wheels to call the `setTime` method after getting objects or records with one of the finder methods --->
 18		<cffunction name="init">
 19			<cfset afterFind("setTime")>
 20		</cffunction>
 21
 22		<cffunction name="setTime">
 23			<cfset arguments.fetchedAt = Now()>
 24			<cfreturn arguments>
 25		</cffunction>
 26	'
 27	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
 28	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
 29	<cfset $registerCallback(type="afterFind", argumentCollection=arguments)>
 30</cffunction>
 31
 32<cffunction name="afterInitialization" returntype="void" access="public" output="false" hint="Registers method(s) that should be called after an object has been initialized."
 33	examples=
 34	'
 35		<!--- Instruct Wheels to call the `fixObj` method --->
 36		<cfset afterInitialization("fixObj")>
 37	'
 38	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
 39	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
 40	<cfset $registerCallback(type="afterInitialization", argumentCollection=arguments)>
 41</cffunction>
 42
 43<cffunction name="beforeValidation" returntype="void" access="public" output="false" hint="Registers method(s) that should be called before an object is validated."
 44	examples=
 45	'
 46		<!--- Instruct Wheels to call the `fixObj` method --->
 47		<cfset beforeValidation("fixObj")>
 48	'
 49	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidationOnCreate,beforeValidationOnUpdate">
 50	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
 51	<cfset $registerCallback(type="beforeValidation", argumentCollection=arguments)>
 52</cffunction>
 53
 54<cffunction name="beforeValidationOnCreate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called before a new object is validated."
 55	examples=
 56	'
 57		<!--- Instruct Wheels to call the `fixObj` method --->
 58		<cfset beforeValidationOnCreate("fixObj")>
 59	'
 60	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnUpdate">
 61	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
 62	<cfset $registerCallback(type="beforeValidationOnCreate", argumentCollection=arguments)>
 63</cffunction>
 64
 65<cffunction name="beforeValidationOnUpdate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called before an existing object is validated."
 66	examples=
 67	'
 68		<!--- Instruct Wheels to call the `fixObj` method --->
 69		<cfset beforeValidationOnUpdate("fixObj")>
 70	'
 71	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate">
 72	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
 73	<cfset $registerCallback(type="beforeValidationOnUpdate", argumentCollection=arguments)>
 74</cffunction>
 75
 76<cffunction name="afterValidation" returntype="void" access="public" output="false" hint="Registers method(s) that should be called after an object is validated."
 77	examples=
 78	'
 79		<!--- Instruct Wheels to call the `fixObj` method --->
 80		<cfset afterValidation("fixObj")>
 81	'
 82	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
 83	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
 84	<cfset $registerCallback(type="afterValidation", argumentCollection=arguments)>
 85</cffunction>
 86
 87<cffunction name="afterValidationOnCreate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called after a new object is validated."
 88	examples=
 89	'
 90		<!--- Instruct Wheels to call the `fixObj` method --->
 91		<cfset afterValidationOnCreate("fixObj")>
 92	'
 93	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
 94	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
 95	<cfset $registerCallback(type="afterValidationOnCreate", argumentCollection=arguments)>
 96</cffunction>
 97
 98<cffunction name="afterValidationOnUpdate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called after an existing object is validated."
 99	examples=
100	'
101		<!--- Instruct Wheels to call the `fixObj` method --->
102		<cfset afterValidationOnUpdate("fixObj")>
103	'
104	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
105	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
106	<cfset $registerCallback(type="afterValidationOnUpdate", argumentCollection=arguments)>
107</cffunction>
108
109<cffunction name="beforeSave" returntype="void" access="public" output="false" hint="Registers method(s) that should be called before an object is saved."
110	examples=
111	'
112		<!--- Instruct Wheels to call the `fixObj` method --->
113		<cfset beforeSave("fixObj")>
114	'
115	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
116	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
117	<cfset $registerCallback(type="beforeSave", argumentCollection=arguments)>
118</cffunction>
119
120<cffunction name="beforeCreate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called before a new object is created."
121	examples=
122	'
123		<!--- Instruct Wheels to call the `fixObj` method --->
124		<cfset beforeCreate("fixObj")>
125	'
126	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
127	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
128	<cfset $registerCallback(type="beforeCreate", argumentCollection=arguments)>
129</cffunction>
130
131<cffunction name="beforeUpdate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called before an existing object is updated."
132	examples=
133	'
134		<!--- Instruct Wheels to call the `fixObj` method --->
135		<cfset beforeUpdate("fixObj")>
136	'
137	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
138	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
139	<cfset $registerCallback(type="beforeUpdate", argumentCollection=arguments)>
140</cffunction>
141
142<cffunction name="afterCreate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called after a new object is created."
143	examples=
144	'
145		<!--- Instruct Wheels to call the `fixObj` method --->
146		<cfset afterCreate("fixObj")>
147	'
148	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
149	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
150	<cfset $registerCallback(type="afterCreate", argumentCollection=arguments)>
151</cffunction>
152
153<cffunction name="afterUpdate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called after an existing object is updated."
154	examples=
155	'
156		<!--- Instruct Wheels to call the `fixObj` method --->
157		<cfset afterUpdate("fixObj")>
158	'
159	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
160	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
161	<cfset $registerCallback(type="afterUpdate", argumentCollection=arguments)>
162</cffunction>
163
164<cffunction name="afterSave" returntype="void" access="public" output="false" hint="Registers method(s) that should be called after an object is saved."
165	examples=
166	'
167		<!--- Instruct Wheels to call the `fixObj` method --->
168		<cfset afterSave("fixObj")>
169	'
170	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
171	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
172	<cfset $registerCallback(type="afterSave", argumentCollection=arguments)>
173</cffunction>
174
175<cffunction name="beforeDelete" returntype="void" access="public" output="false" hint="Registers method(s) that should be called before an object is deleted."
176	examples=
177	'
178		<!--- Instruct Wheels to call the `fixObj` method --->
179		<cfset beforeDelete("fixObj")>
180	'
181	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterDelete,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
182	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
183	<cfset $registerCallback(type="beforeDelete", argumentCollection=arguments)>
184</cffunction>
185
186<cffunction name="afterDelete" returntype="void" access="public" output="false" hint="Registers method(s) that should be called after an object is deleted."
187	examples=
188	'
189		<!--- Instruct Wheels to call the `fixObj` method --->
190		<cfset afterDelete("fixObj")>
191	'
192	categories="model-initialization,callbacks" chapters="object-callbacks" functions="afterCreate,afterFind,afterInitialization,afterNew,afterSave,afterUpdate,afterValidation,afterValidationOnCreate,afterValidationOnUpdate,beforeCreate,beforeDelete,beforeSave,beforeUpdate,beforeValidation,beforeValidationOnCreate,beforeValidationOnUpdate">
193	<cfargument name="methods" type="string" required="false" default="" hint="See documentation for @afterNew.">
194	<cfset $registerCallback(type="afterDelete", argumentCollection=arguments)>
195</cffunction>
196
197<!--- PRIVATE MODEL INITIALIZATION METHODS --->
198
199<cffunction name="$registerCallback" returntype="void" access="public" output="false">
200	<cfargument name="type" type="string" required="true">
201	<cfargument name="methods" type="string" required="true">
202	<cfscript>
203		var loc = {};
204		// create this type in the array if it doesn't already exist
205		if (not StructKeyExists(variables.wheels.class.callbacks,arguments.type))
206			variables.wheels.class.callbacks[arguments.type] = ArrayNew(1);
207		loc.existingCallbacks = ArrayToList(variables.wheels.class.callbacks[arguments.type]);
208		if (StructKeyExists(arguments, "method"))
209			arguments.methods = arguments.method;
210		arguments.methods = $listClean(arguments.methods);
211		loc.iEnd = ListLen(arguments.methods);
212		for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
213			if (!ListFindNoCase(loc.existingCallbacks, ListGetAt(arguments.methods, loc.i)))
214				ArrayAppend(variables.wheels.class.callbacks[arguments.type], ListGetAt(arguments.methods, loc.i));
215	</cfscript>
216</cffunction>
217
218<cffunction name="$clearCallbacks" returntype="void" access="public" output="false" hint="Removes all callbacks registered for this model. Pass in the `type` argument to only remove callbacks for that specific type.">
219	<cfargument name="type" type="string" required="false" default="" hint="Type of callback (`beforeSave` etc).">
220	<cfscript>
221		var loc = {};
222		// clean up the list of types passed in
223		arguments.type = $listClean(list="#arguments.type#", returnAs="array");
224		// no type(s) was passed in. get all the callback types registered
225		if (ArrayIsEmpty(arguments.type))
226		{
227			arguments.type = ListToArray(StructKeyList(variables.wheels.class.callbacks));
228		}
229		// loop through each callback type and clear it
230		loc.iEnd = ArrayLen(arguments.type);
231		for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
232		{
233			variables.wheels.class.callbacks[arguments.type[loc.i]] = [];
234		}
235	</cfscript>
236</cffunction>
237
238<cffunction name="$callbacks" returntype="any" access="public" output="false" hint="Returns all registered callbacks for this model (as a struct). Pass in the `type` argument to only return callbacks for that specific type (as an array).">
239	<cfargument name="type" type="string" required="false" default="" hint="See documentation for @$clearCallbacks.">
240	<cfscript>
241		if (Len(arguments.type))
242		{
243			if (StructKeyExists(variables.wheels.class.callbacks,arguments.type))
244				return variables.wheels.class.callbacks[arguments.type];
245			return ArrayNew(1);
246		}
247		return variables.wheels.class.callbacks;
248	</cfscript>
249</cffunction>
250
251
252<!--- PRIVATE MODEL OBJECT METHODS --->
253
254<cffunction name="$callback" returntype="boolean" access="public" output="false" hint="Executes all callback methods for a specific type. Will stop execution on the first callback that returns `false`.">
255	<cfargument name="type" type="string" required="true" hint="See documentation for @$clearCallbacks.">
256	<cfargument name="execute" type="boolean" required="true" hint="A query is passed in here for `afterFind` callbacks.">
257	<cfargument name="collection" type="any" required="false" default="" hint="A query is passed in here for `afterFind` callbacks.">
258	<cfscript>
259		var loc = {};
260
261		if (!arguments.execute)
262			return true;
263
264		// get all callbacks for the type and loop through them all until the end or one of them returns false
265		loc.callbacks = $callbacks(arguments.type);
266		loc.iEnd = ArrayLen(loc.callbacks);
267		for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
268		{
269			loc.method = loc.callbacks[loc.i];
270			if (arguments.type == "afterFind")
271			{
272				// since this is an afterFind callback we need to handle it differently
273				if (IsQuery(arguments.collection))
274				{
275					loc.returnValue = $queryCallback(method=loc.method, collection=arguments.collection);
276				}
277				else
278				{
279					loc.invokeArgs = properties();
280					loc.returnValue = $invoke(method=loc.method, invokeArgs=loc.invokeArgs);
281					if (StructKeyExists(loc, "returnValue") && IsStruct(loc.returnValue))
282					{
283						setProperties(loc.returnValue);
284						StructDelete(loc, "returnValue");
285					}
286				}
287			}
288			else
289			{
290				// this is a regular callback so just call the method
291				loc.returnValue = $invoke(method=loc.method);
292			}
293
294			// break the loop if the callback returned false
295			if (StructKeyExists(loc, "returnValue") && IsBoolean(loc.returnValue) && !loc.returnValue)
296				break;
297		}
298
299		// return true by default (happens when no callbacks are set or none of the callbacks returned a result)
300		if (!StructKeyExists(loc, "returnValue"))
301			loc.returnValue = true;
302	</cfscript>
303	<cfreturn loc.returnValue>
304</cffunction>
305
306<cffunction name="$queryCallback" returntype="boolean" access="public" output="false" hint="Loops over the passed in query, calls the callback method for each row and changes the query based on the arguments struct that is passed back.">
307	<cfargument name="method" type="string" required="true" hint="The method to call.">
308	<cfargument name="collection" type="query" required="true" hint="See documentation for @$callback.">
309	<cfscript>
310		var loc = {};
311
312		// we return true by default
313		// will be overridden only if the callback method returns false on one of the iterations
314		loc.returnValue = true;
315
316		// loop over all query rows and execute the callback method for each
317		loc.jEnd = arguments.collection.recordCount;
318		for (loc.j=1; loc.j <= loc.jEnd; loc.j++)
319		{
320			// get the values in the current query row so that we can pass them in as arguments to the callback method
321			loc.invokeArgs = {};
322			loc.kEnd = ListLen(arguments.collection.columnList);
323			for (loc.k=1; loc.k <= loc.kEnd; loc.k++)
324			{
325				loc.kItem = ListGetAt(arguments.collection.columnList, loc.k);
326				try // coldfusion has a problem with empty strings in queries for bit types
327				{
328					loc.invokeArgs[loc.kItem] = arguments.collection[loc.kItem][loc.j];
329				}
330				catch (Any e)
331				{
332					loc.invokeArgs[loc.kItem] = "";
333				}
334			}
335
336			// execute the callback method
337			loc.result = $invoke(method=arguments.method, invokeArgs=loc.invokeArgs);
338
339			if (StructKeyExists(loc, "result"))
340			{
341				if (IsStruct(loc.result))
342				{
343					// the arguments struct was returned so we need to add the changed values to the query row
344					for (loc.key in loc.result)
345					{
346						// add a new column to the query if a value was passed back for a column that did not exist originally
347						if (!ListFindNoCase(arguments.collection.columnList, loc.key))
348							QueryAddColumn(arguments.collection, loc.key, ArrayNew(1));
349						arguments.collection[loc.key][loc.j] = loc.result[loc.key];
350					}
351				}
352				else if (IsBoolean(loc.result) && !loc.result)
353				{
354					// break the loop and return false if the callback returned false
355					loc.returnValue = false;
356					break;
357				}
358			}
359		}
360
361		// update the request with a hash of the query if it changed so that we can find it with pagination
362		loc.querykey = $hashedKey(arguments.collection);
363		if (!StructKeyExists(request.wheels, loc.querykey))
364			request.wheels[loc.querykey] = variables.wheels.class.modelName;
365	</cfscript>
366	<cfreturn loc.returnValue>
367</cffunction>