PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/wheels/model/validations.cfm

http://github.com/raulriera/SplashCMS
ColdFusion | 483 lines | 446 code | 27 blank | 10 comment | 118 complexity | d212b46726918706183e733a659801d8 MD5 | raw file
  1. <!--- PUBLIC MODEL INITIALIZATION METHODS --->
  2. <!--- high level validation helpers --->
  3. <cffunction name="validatesConfirmationOf" returntype="void" access="public" output="false" hint="Validates that the value of the specified property also has an identical confirmation value (common when having a user type in their email address, choosing a password etc). The confirmation value only exists temporarily and never gets saved to the database. By convention the confirmation property has to be named the same as the property with ""Confirmation"" appended at the end. Using the password example, to confirm our `password` property we would create a property called `passwordConfirmation`."
  4. examples=
  5. '
  6. <!--- Make sure that the user has to confirm their password correctly the first time they register (usually done by typing it again in a second form field) --->
  7. <cfset validatesConfirmationOf(property="password", when="onCreate", message="Please confirm your chosen password properly!")>
  8. '
  9. categories="model-initialization,validation" chapters="object-validation" functions="validatesExclusionOf,validatesFormatOf,validatesInclusionOf,validatesLengthOf,validatesNumericalityOf,validatesPresenceOf,validatesUniquenessOf">
  10. <cfargument name="properties" type="string" required="false" default="" hint="Name of property or list of property names to validate against (can also be called with the `property` argument).">
  11. <cfargument name="message" type="string" required="false" default="#application.wheels.functions.validatesConfirmationOf.message#" hint="Supply a custom error message here to override the built-in one.">
  12. <cfargument name="when" type="string" required="false" default="onSave" hint="Pass in `onCreate` or `onUpdate` to limit when this validation occurs (by default validation will occur on both create and update, i.e. `onSave`).">
  13. <cfargument name="if" type="string" required="false" default="" hint="String expression to be evaluated that decides if validation will be run (if the expression returns `true` validation will run).">
  14. <cfargument name="unless" type="string" required="false" default="" hint="String expression to be evaluated that decides if validation will be run (if the expression returns `false` validation will run).">
  15. <cfset $registerValidation(methods="$validateConfirmationOf", argumentCollection=arguments)>
  16. </cffunction>
  17. <cffunction name="validatesExclusionOf" returntype="void" access="public" output="false" hint="Validates that the value of the specified property does not exist in the supplied list."
  18. examples=
  19. '
  20. <!--- Do not allow "PHP" or "Fortran" to be saved to the database as a cool language --->
  21. <cfset validatesExclusionOf(property="coolLanguage", list="php,fortran", message="Haha, you can not be serious, try again please.")>
  22. '
  23. categories="model-initialization,validation" chapters="object-validation" functions="validatesConfirmationOf,validatesExclusionOf,validatesFormatOf,validatesInclusionOf,validatesLengthOf,validatesNumericalityOf,validatesPresenceOf,validatesUniquenessOf">
  24. <cfargument name="properties" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  25. <cfargument name="list" type="string" required="true" hint="Single value or list of values that should not be allowed.">
  26. <cfargument name="message" type="string" required="false" default="#application.wheels.functions.validatesExclusionOf.message#" hint="See documentation for @validatesConfirmationOf.">
  27. <cfargument name="when" type="string" required="false" default="onSave" hint="See documentation for @validatesConfirmationOf.">
  28. <cfargument name="allowBlank" type="boolean" required="false" default="#application.wheels.functions.validatesExclusionOf.allowBlank#" hint="If set to `true`, validation will be skipped if the property value is an empty string or doesn't exist at all.">
  29. <cfargument name="if" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  30. <cfargument name="unless" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  31. <cfscript>
  32. arguments.list = Replace(arguments.list, ", ", ",", "all");
  33. $registerValidation(methods="$validateExclusionOf", argumentCollection=arguments);
  34. </cfscript>
  35. </cffunction>
  36. <cffunction name="validatesFormatOf" returntype="void" access="public" output="false" hint="Validates that the value of the specified property is formatted correctly by matching it against a regular expression using the `regEx` argument and/or against a built-in CFML validation type (`creditcard`, `date`, `email` etc) using the `type` argument."
  37. examples=
  38. '
  39. <!--- Make sure that the user has entered a correct credit card --->
  40. <cfset validatesFormatOf(property="cc", type="creditcard")>
  41. <!--- Make sure that the user has entered an email address ending with the `.se` domain when the `ipCheck` methods returns `true` and it''s not Sunday, also supply a custom error message that overrides the Wheels default one --->
  42. <cfset validatesFormatOf(property="email", regEx="^.*@.*\.se$", if="ipCheck()", unless="DayOfWeek() IS 1" message="Sorry, you must have a Swedish email address to use this website")>
  43. '
  44. categories="model-initialization,validation" chapters="object-validation" functions="validatesConfirmationOf,validatesExclusionOf,validatesInclusionOf,validatesLengthOf,validatesNumericalityOf,validatesPresenceOf,validatesUniquenessOf">
  45. <cfargument name="properties" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  46. <cfargument name="regEx" type="string" required="false" default="" hint="Regular expression to verify against.">
  47. <cfargument name="type" type="string" required="false" default="" hint="One of the following types to verify against: `creditcard`, `date`, `email`, `eurodate`, `guid`, `social_security_number`, `ssn`, `telephone`, `time`, `URL`, `USdate`, `UUID`, `variableName`, `zipcode` (will be passed through to CFML's `isValid` function).">
  48. <cfargument name="message" type="string" required="false" default="#application.wheels.functions.validatesFormatOf.message#" hint="See documentation for @validatesConfirmationOf.">
  49. <cfargument name="when" type="string" required="false" default="onSave" hint="See documentation for @validatesConfirmationOf.">
  50. <cfargument name="allowBlank" type="boolean" required="false" default="#application.wheels.functions.validatesFormatOf.allowBlank#" hint="See documentation for @validatesExclusionOf.">
  51. <cfargument name="if" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  52. <cfargument name="unless" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  53. <cfscript>
  54. if (application.wheels.showErrorInformation)
  55. {
  56. if (Len(arguments.type) && !ListFindNoCase("creditcard,date,email,eurodate,guid,social_security_number,ssn,telephone,time,URL,USdate,UUID,variableName,zipcode", arguments.type))
  57. $throw(type="Wheels.IncorrectArguments", message="The `#arguments.type#` type is not supported.", extendedInfo="Use one of the supported types: `creditcard`, `date`, `email`, `eurodate`, `guid`, `social_security_number`, `ssn`, `telephone`, `time`, `URL`, `USdate`, `UUID`, `variableName`, `zipcode`");
  58. }
  59. $registerValidation(methods="$validateFormatOf", argumentCollection=arguments);
  60. </cfscript>
  61. </cffunction>
  62. <cffunction name="validatesInclusionOf" returntype="void" access="public" output="false" hint="Validates that the value of the specified property exists in the supplied list."
  63. examples=
  64. '
  65. <!--- Make sure that the user selects either "Wheels" or "Rails" as their framework --->
  66. <cfset validatesInclusionOf(property="frameworkOfChoice", list="wheels,rails", message="Please try again and this time select a decent framework.")>
  67. '
  68. categories="model-initialization,validation" chapters="object-validation" functions="validatesConfirmationOf,validatesExclusionOf,validatesFormatOf,validatesLengthOf,validatesNumericalityOf,validatesPresenceOf,validatesUniquenessOf">
  69. <cfargument name="properties" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  70. <cfargument name="list" type="string" required="true" hint="List of allowed values.">
  71. <cfargument name="message" type="string" required="false" default="#application.wheels.functions.validatesInclusionOf.message#" hint="See documentation for @validatesConfirmationOf.">
  72. <cfargument name="when" type="string" required="false" default="onSave" hint="See documentation for @validatesConfirmationOf.">
  73. <cfargument name="allowBlank" type="boolean" required="false" default="#application.wheels.functions.validatesInclusionOf.allowBlank#" hint="See documentation for @validatesExclusionOf.">
  74. <cfargument name="if" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  75. <cfargument name="unless" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  76. <cfscript>
  77. arguments.list = Replace(arguments.list, ", ", ",", "all");
  78. $registerValidation(methods="$validateInclusionOf", argumentCollection=arguments);
  79. </cfscript>
  80. </cffunction>
  81. <cffunction name="validatesLengthOf" returntype="void" access="public" output="false" hint="Validates that the value of the specified property matches the length requirements supplied. Use the `exactly`, `maximum`, `minimum` and `within` arguments to specify the length requirements."
  82. examples=
  83. '
  84. <!--- Make sure that the `firstname` and `lastName` properties are not more than 50 characters and use square brackets to dynamically insert the property name when the error message is displayed to the user (the `firstName` property will be displayed as "first name") --->
  85. <cfset validatesLengthOf(properties="firstName,lastName", maximum=50, message="Please shorten your [property] please, 50 characters is the maximum length allowed.")>
  86. <!--- Make sure that the `password` property is between 4 and 15 characters --->
  87. <cfset validatesLengthOf(property="password", within="4,20", message="The password length has to be between 4 and 20 characters.")>
  88. '
  89. categories="model-initialization,validation" chapters="object-validation" functions="validatesConfirmationOf,validatesExclusionOf,validatesFormatOf,validatesInclusionOf,validatesNumericalityOf,validatesPresenceOf,validatesUniquenessOf">
  90. <cfargument name="properties" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  91. <cfargument name="message" type="string" required="false" default="#application.wheels.functions.validatesLengthOf.message#" hint="See documentation for @validatesConfirmationOf.">
  92. <cfargument name="when" type="string" required="false" default="onSave" hint="See documentation for @validatesConfirmationOf.">
  93. <cfargument name="allowBlank" type="boolean" required="false" default="#application.wheels.functions.validatesLengthOf.allowBlank#" hint="See documentation for @validatesExclusionOf.">
  94. <cfargument name="exactly" type="numeric" required="false" default="#application.wheels.functions.validatesLengthOf.exactly#" hint="The exact length that the property value has to be.">
  95. <cfargument name="maximum" type="numeric" required="false" default="#application.wheels.functions.validatesLengthOf.maximum#" hint="The maximum length that the property value has to be.">
  96. <cfargument name="minimum" type="numeric" required="false" default="#application.wheels.functions.validatesLengthOf.minimum#" hint="The minimum length that the property value has to be.">
  97. <cfargument name="within" type="string" required="false" default="#application.wheels.functions.validatesLengthOf.within#" hint="A list of two values (minimum and maximum) that the length of the property value has to fall within.">
  98. <cfargument name="if" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  99. <cfargument name="unless" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  100. <cfscript>
  101. if (Len(arguments.within))
  102. arguments.within = ListToArray(Replace(arguments.within, ", ", ",", "all"));
  103. $registerValidation(methods="$validateLengthOf", argumentCollection=arguments);
  104. </cfscript>
  105. </cffunction>
  106. <cffunction name="validatesNumericalityOf" returntype="void" access="public" output="false" hint="Validates that the value of the specified property is numeric."
  107. examples=
  108. '
  109. <!--- Make sure that the score is a number with no decimals but only when a score is supplied (setting `allowBlank` to `true` means that objects are allowed to be saved without scores, typically resulting in `NULL` values being inserted in the database table) --->
  110. <cfset validatesNumericalityOf(property="score", onlyInteger=true, allowBlank=true, message="Please enter a correct score.")>
  111. '
  112. categories="model-initialization,validation" chapters="object-validation" functions="validatesConfirmationOf,validatesExclusionOf,validatesFormatOf,validatesInclusionOf,validatesLengthOf,validatesPresenceOf,validatesUniquenessOf">
  113. <cfargument name="properties" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  114. <cfargument name="message" type="string" required="false" default="#application.wheels.functions.validatesNumericalityOf.message#" hint="See documentation for @validatesConfirmationOf.">
  115. <cfargument name="when" type="string" required="false" default="onSave" hint="See documentation for @validatesConfirmationOf.">
  116. <cfargument name="allowBlank" type="boolean" required="false" default="#application.wheels.functions.validatesNumericalityOf.allowBlank#" hint="See documentation for @validatesExclusionOf.">
  117. <cfargument name="onlyInteger" type="boolean" required="false" default="#application.wheels.functions.validatesNumericalityOf.onlyInteger#" hint="Specifies whether the property value has to be an integer.">
  118. <cfargument name="if" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  119. <cfargument name="unless" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  120. <cfset $registerValidation(methods="$validateNumericalityOf", argumentCollection=arguments)>
  121. </cffunction>
  122. <cffunction name="validatesPresenceOf" returntype="void" access="public" output="false" hint="Validates that the specified property exists and that its value is not blank."
  123. examples=
  124. '
  125. <!--- Make sure that the user data can not be saved to the database without the `emailAddress` property (it has to exist and not be an empty string) --->
  126. <cfset validatesPresenceOf("emailAddress")>
  127. '
  128. categories="model-initialization,validation" chapters="object-validation" functions="validatesConfirmationOf,validatesExclusionOf,validatesFormatOf,validatesInclusionOf,validatesLengthOf,validatesNumericalityOf,validatesUniquenessOf">
  129. <cfargument name="properties" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  130. <cfargument name="message" type="string" required="false" default="#application.wheels.functions.validatesPresenceOf.message#" hint="See documentation for @validatesConfirmationOf.">
  131. <cfargument name="when" type="string" required="false" default="onSave" hint="See documentation for @validatesConfirmationOf.">
  132. <cfargument name="if" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  133. <cfargument name="unless" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  134. <cfset $registerValidation(methods="$validatePresenceOf", argumentCollection=arguments)>
  135. </cffunction>
  136. <cffunction name="validatesUniquenessOf" returntype="void" access="public" output="false" hint="Validates that the value of the specified property is unique in the database table. Useful for ensuring that two users can't sign up to a website with identical screen names for example. When a new record is created a check is made to make sure that no record already exists in the database with the given value for the specified property. When the record is updated the same check is made but disregarding the record itself."
  137. examples=
  138. '
  139. <!--- Make sure that two users with the same screen name won''t ever exist in the database (although to be 100% safe you should consider using database locking as well) --->
  140. <cfset validatesUniquenessOf(property="username", message="Sorry, that username is already taken.")>
  141. <!--- Same as above but allow identical user names as long as they belong to a different account --->
  142. <cfset validatesUniquenessOf(property="username", scope="accountId")>
  143. '
  144. categories="model-initialization,validation" chapters="object-validation" functions="validatesConfirmationOf,validatesExclusionOf,validatesFormatOf,validatesInclusionOf,validatesLengthOf,validatesNumericalityOf,validatesPresenceOf">
  145. <cfargument name="properties" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  146. <cfargument name="message" type="string" required="false" default="#application.wheels.functions.validatesUniquenessOf.message#" hint="See documentation for @validatesConfirmationOf.">
  147. <cfargument name="when" type="string" required="false" default="onSave" hint="See documentation for @validatesConfirmationOf.">
  148. <cfargument name="allowBlank" type="boolean" required="false" default="#application.wheels.functions.validatesUniquenessOf.allowBlank#" hint="See documentation for @validatesExclusionOf.">
  149. <cfargument name="scope" type="string" required="false" default="" hint="One or more properties by which to limit the scope of the uniqueness constraint.">
  150. <cfargument name="if" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  151. <cfargument name="unless" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  152. <cfscript>
  153. arguments.scope = Replace(arguments.scope, ", ", ",", "all");
  154. $registerValidation(methods="$validateUniquenessOf", argumentCollection=arguments);
  155. </cfscript>
  156. </cffunction>
  157. <!--- low level validation --->
  158. <cffunction name="validate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called to validate objects before they are saved."
  159. examples=
  160. '
  161. <cffunction name="init">
  162. <!--- Register the `check` method below to be called to validate objects before they are saved --->
  163. <cfset validate("check")>
  164. </cffunction>
  165. <cffunction name="check">
  166. </cffunction>
  167. '
  168. categories="model-initialization,validation" chapters="object-validation" functions="validateOnCreate,validateOnUpdate">
  169. <cfargument name="methods" type="string" required="false" default="" hint="Method name or list of method names to call (can also be called with the `method` argument).">
  170. <cfargument name="if" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  171. <cfargument name="unless" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  172. <cfset $registerValidation(when="onSave", argumentCollection=arguments)>
  173. </cffunction>
  174. <cffunction name="validateOnCreate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called to validate new objects before they are inserted."
  175. examples=
  176. '
  177. <cffunction name="init">
  178. <!--- Register the `check` method below to be called to validate new objects before they are inserted --->
  179. <cfset validateOnCreate("check")>
  180. </cffunction>
  181. <cffunction name="check">
  182. </cffunction>
  183. '
  184. categories="model-initialization,validation" chapters="object-validation" functions="validate,validateOnUpdate">
  185. <cfargument name="methods" type="string" required="false" default="" hint="See documentation for @validate.">
  186. <cfargument name="if" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  187. <cfargument name="unless" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  188. <cfset $registerValidation(when="onCreate", argumentCollection=arguments)>
  189. </cffunction>
  190. <cffunction name="validateOnUpdate" returntype="void" access="public" output="false" hint="Registers method(s) that should be called to validate existing objects before they are updated."
  191. examples=
  192. '
  193. <cffunction name="init">
  194. <!--- Register the `check` method below to be called to validate existing objects before they are updated --->
  195. <cfset validateOnUpdate("check")>
  196. </cffunction>
  197. <cffunction name="check">
  198. </cffunction>
  199. '
  200. categories="model-initialization,validation" chapters="object-validation" functions="validate,validateOnCreate">
  201. <cfargument name="methods" type="string" required="false" default="" hint="See documentation for @validate.">
  202. <cfargument name="if" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  203. <cfargument name="unless" type="string" required="false" default="" hint="See documentation for @validatesConfirmationOf.">
  204. <cfset $registerValidation(when="onUpdate", argumentCollection=arguments)>
  205. </cffunction>
  206. <!--- PUBLIC MODEL OBJECT METHODS --->
  207. <cffunction name="valid" returntype="boolean" access="public" output="false" hint="Runs the validation on the object and returns `true` if it passes it. Wheels will run the validation process automatically whenever an object is saved to the database but sometimes it's useful to be able to run this method to see if the object is valid without saving it to the database."
  208. examples=
  209. '
  210. <!--- Check if a user is valid before proceeding with execution --->
  211. <cfif user.valid()>
  212. <!--- Do something here --->
  213. </cfif>
  214. '
  215. categories="model-object" chapters="object-validation" functions="">
  216. <cfscript>
  217. var loc = {};
  218. loc.returnValue = false;
  219. if ($callback("beforeValidation"))
  220. {
  221. if (isNew())
  222. {
  223. // if this is a brand new object that has not been saved to the database we validate the `onCreate` methods (`onSave` methods are always called)
  224. if ($callback("beforeValidationOnCreate") && $validate("onSave") && $validate("onCreate") && $callback("afterValidation") && $callback("afterValidationOnCreate"))
  225. loc.returnValue = true;
  226. }
  227. else
  228. {
  229. // if this record already exists in the database we validate the `onUpdate` methods
  230. if ($callback("beforeValidationOnUpdate") && $validate("onSave") && $validate("onUpdate") && $callback("afterValidation") && $callback("afterValidationOnUpdate"))
  231. loc.returnValue = true;
  232. }
  233. }
  234. </cfscript>
  235. <cfreturn loc.returnValue>
  236. </cffunction>
  237. <!--- PRIVATE MODEL INITIALIZATION METHODS --->
  238. <cffunction name="$registerValidation" returntype="void" access="public" output="false" hint="Called from the high level validation helpers to register the validation in the class struct of the model.">
  239. <cfargument name="when" type="string" required="true">
  240. <cfscript>
  241. var loc = {};
  242. // combine `method`/`methods` and `property`/`properties` into one variables for easier processing below
  243. if (StructKeyExists(arguments, "method"))
  244. {
  245. arguments.methods = arguments.method;
  246. StructDelete(arguments, "method");
  247. }
  248. if (StructKeyExists(arguments, "property"))
  249. {
  250. arguments.properties = arguments.property;
  251. StructDelete(arguments, "property");
  252. }
  253. // when using the core validations the developer needs to pass in specific properties, throw an error if they haven't
  254. if (application.wheels.showErrorInformation)
  255. {
  256. if (StructKeyExists(arguments, "properties"))
  257. {
  258. if (!Len(arguments.properties))
  259. $throw(type="Wheels.IncorrectArguments", message="The `property` or `properties` argument is required but was not passed in.", extendedInfo="Please pass in the names of the properties you want to validate. Use either the `property` argument (for a single property) or the `properties` argument (for a list of properties) to do this.");
  260. }
  261. }
  262. // loop through all methods and properties and add info for each to the `class` struct
  263. loc.iEnd = ListLen(arguments.methods);
  264. for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
  265. {
  266. // only loop once by default (will be used on the lower level validation helpers that do not take arguments: `validate`, `validateOnCreate` and `validateOnUpdate`)
  267. loc.jEnd = 1;
  268. if (StructKeyExists(arguments, "properties"))
  269. loc.jEnd = ListLen(arguments.properties);
  270. for (loc.j=1; loc.j <= loc.jEnd; loc.j++)
  271. {
  272. loc.validation = {};
  273. loc.validation.method = Trim(ListGetAt(arguments.methods, loc.i));
  274. loc.validation.args = Duplicate(arguments);
  275. if (StructKeyExists(arguments, "properties"))
  276. {
  277. loc.validation.args.property = Trim(ListGetAt(loc.validation.args.properties, loc.j));
  278. loc.validation.args.message = $validationErrorMessage(message=loc.validation.args.message, property=loc.validation.args.property);
  279. }
  280. StructDelete(loc.validation.args, "when");
  281. StructDelete(loc.validation.args, "methods");
  282. StructDelete(loc.validation.args, "properties");
  283. ArrayAppend(variables.wheels.class.validations[arguments.when], loc.validation);
  284. }
  285. }
  286. </cfscript>
  287. </cffunction>
  288. <cffunction name="$validationErrorMessage" returntype="string" access="public" output="false" hint="Creates nicer looking error text by humanizing the property name and capitalizing it when appropriate.">
  289. <cfargument name="message" type="string" required="true">
  290. <cfargument name="property" type="string" required="true">
  291. <cfscript>
  292. var returnValue = "";
  293. // turn property names into lower cased words
  294. returnValue = Replace(arguments.message, "[property]", LCase(humanize(arguments.property)), "all");
  295. // capitalize the first word in the property name if it comes first in the sentence
  296. if (Left(arguments.message, 10) == "[property]")
  297. returnValue = capitalize(returnValue);
  298. </cfscript>
  299. <cfreturn returnValue>
  300. </cffunction>
  301. <!--- PRIVATE MODEL OBJECT METHODS --->
  302. <cffunction name="$validate" returntype="boolean" access="public" output="false" hint="Runs all the validation methods setup on the object and adds errors as it finds them. Returns `true` if no errors were added, `false` otherwise.">
  303. <cfargument name="type" type="string" required="true">
  304. <cfscript>
  305. var loc = {};
  306. // loop through all validations for passed in type (`onSave`, `onCreate` etc) that has been set on this model object
  307. loc.iEnd = ArrayLen(variables.wheels.class.validations[arguments.type]);
  308. for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
  309. {
  310. loc.thisValidation = variables.wheels.class.validations[arguments.type][loc.i];
  311. if ($evaluateValidationCondition(argumentCollection=loc.thisValidation.args))
  312. {
  313. if (loc.thisValidation.method == "$validatePresenceOf")
  314. {
  315. // if the property does not exist or if it's blank we add an error on the object (for all other validation types we call corresponding methods below instead)
  316. if (!StructKeyExists(this, loc.thisValidation.args.property) || !Len(this[loc.thisValidation.args.property]))
  317. addError(property=loc.thisValidation.args.property, message=loc.thisValidation.args.message);
  318. }
  319. else
  320. {
  321. // if the validation set does not allow blank values we can set an error right away, otherwise we call a method to run the actual check
  322. if (StructKeyExists(loc.thisValidation.args, "property") && StructKeyExists(loc.thisValidation.args, "allowBlank") && !loc.thisValidation.args.allowBlank && (!StructKeyExists(this, loc.thisValidation.args.property) || !Len(this[loc.thisValidation.args.property])))
  323. addError(property=loc.thisValidation.args.property, message=loc.thisValidation.args.message);
  324. else if (!StructKeyExists(loc.thisValidation.args, "property") || (StructKeyExists(this, loc.thisValidation.args.property) && Len(this[loc.thisValidation.args.property])))
  325. $invoke(method=loc.thisValidation.method, argumentCollection=loc.thisValidation.args);
  326. }
  327. }
  328. }
  329. // now that we have run all the validation checks we can return `true` if no errors exist on the object, `false` otherwise
  330. loc.returnValue = !hasErrors();
  331. </cfscript>
  332. <cfreturn loc.returnValue>
  333. </cffunction>
  334. <cffunction name="$evaluateValidationCondition" returntype="boolean" access="public" output="false" hint="Evaluates the condition to determine if the validation should be executed.">
  335. <cfscript>
  336. var returnValue = false;
  337. // proceed with validation when `if` has been supplied and it evaluates to `true` or when `unless` has been supplied and it evaluates to `false`
  338. // if both `if` and `unless` have been supplied though, they both need to be evaluated correctly (`true`/`false` that is) for validation to proceed
  339. if ((!StructKeyExists(arguments, "if") || !Len(arguments.if) || Evaluate(arguments.if)) && (!StructKeyExists(arguments, "unless") || !Len(arguments.unless) || !Evaluate(arguments.unless)))
  340. returnValue = true;
  341. </cfscript>
  342. <cfreturn returnValue>
  343. </cffunction>
  344. <cffunction name="$validateConfirmationOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesConfirmationOf method.">
  345. <cfscript>
  346. var loc = {};
  347. loc.virtualConfirmProperty = arguments.property & "Confirmation";
  348. if (StructKeyExists(this, loc.virtualConfirmProperty) && this[arguments.property] != this[loc.virtualConfirmProperty])
  349. addError(property=loc.virtualConfirmProperty, message=arguments.message);
  350. </cfscript>
  351. </cffunction>
  352. <cffunction name="$validateExclusionOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesExclusionOf method.">
  353. <cfscript>
  354. if (ListFindNoCase(arguments.list, this[arguments.property]))
  355. addError(property=arguments.property, message=arguments.message);
  356. </cfscript>
  357. </cffunction>
  358. <cffunction name="$validateFormatOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesFormatOf method.">
  359. <cfscript>
  360. if ((Len(arguments.regEx) && !REFindNoCase(arguments.regEx, this[arguments.property])) || (Len(arguments.type) && !IsValid(arguments.type, this[arguments.property])))
  361. addError(property=arguments.property, message=arguments.message);
  362. </cfscript>
  363. </cffunction>
  364. <cffunction name="$validateInclusionOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesInclusionOf method.">
  365. <cfscript>
  366. if (!ListFindNoCase(arguments.list, this[arguments.property]))
  367. addError(property=arguments.property, message=arguments.message);
  368. </cfscript>
  369. </cffunction>
  370. <cffunction name="$validateLengthOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesLengthOf method.">
  371. <cfscript>
  372. if (arguments.maximum)
  373. {
  374. if (Len(this[arguments.property]) > arguments.maximum)
  375. addError(property=arguments.property, message=arguments.message);
  376. }
  377. else if (arguments.minimum)
  378. {
  379. if (Len(this[arguments.property]) < arguments.minimum)
  380. addError(property=arguments.property, message=arguments.message);
  381. }
  382. else if (arguments.exactly)
  383. {
  384. if (Len(this[arguments.property]) != arguments.exactly)
  385. addError(property=arguments.property, message=arguments.message);
  386. }
  387. else if (IsArray(arguments.within) && ArrayLen(arguments.within))
  388. {
  389. if (Len(this[arguments.property]) < arguments.within[1] || Len(this[arguments.property]) > arguments.within[2])
  390. addError(property=arguments.property, message=arguments.message);
  391. }
  392. </cfscript>
  393. </cffunction>
  394. <cffunction name="$validateNumericalityOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesNumericalityOf method.">
  395. <cfscript>
  396. if (!IsNumeric(this[arguments.property]))
  397. addError(property=arguments.property, message=arguments.message);
  398. else if (arguments.onlyInteger && Round(this[arguments.property]) != this[arguments.property])
  399. addError(property=arguments.property, message=arguments.message);
  400. </cfscript>
  401. </cffunction>
  402. <cffunction name="$validateUniquenessOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesUniquenessOf method.">
  403. <cfscript>
  404. var loc = {};
  405. // create the WHERE clause to be used in the query that checks if an identical value already exists
  406. // wrap value in single quotes unless it's numeric
  407. // example: "userName='Joe'"
  408. loc.where = arguments.property & "=";
  409. if (!IsNumeric(this[arguments.property]))
  410. loc.where = loc.where & "'";
  411. loc.where = loc.where & this[arguments.property];
  412. if (!IsNumeric(this[arguments.property]))
  413. loc.where = loc.where & "'";
  414. // add scopes to the WHERE clause if passed in, this means that checks for other properties are done in the WHERE clause as well
  415. // example: "userName='Joe'" becomes "userName='Joe' AND account=1" if scope is "account" for example
  416. if (Len(arguments.scope))
  417. {
  418. loc.iEnd = ListLen(arguments.scope);
  419. for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
  420. {
  421. loc.where = loc.where & " AND ";
  422. loc.property = Trim(ListGetAt(arguments.scope, loc.i));
  423. loc.where = loc.where & loc.property & "=";
  424. if (!IsNumeric(this[loc.property]))
  425. loc.where = loc.where & "'";
  426. loc.where = loc.where & this[loc.property];
  427. if (!IsNumeric(this[loc.property]))
  428. loc.where = loc.where & "'";
  429. }
  430. }
  431. // try to fetch existing object from the database
  432. loc.existingObject = findOne(where=loc.where, reload=true);
  433. // we add an error if an object was found in the database and the current object is either not saved yet or not the same as the one in the database
  434. if (IsObject(loc.existingObject) && (isNew() || loc.existingObject.key() != key($persisted=true)))
  435. addError(property=arguments.property, message=arguments.message);
  436. </cfscript>
  437. </cffunction>