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