PageRenderTime 40ms CodeModel.GetById 30ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/wheels/model/onmissingmethod.cfm

http://cfwheels.googlecode.com/
ColdFusion | 397 lines | 394 code | 3 blank | 0 comment | 56 complexity | c35fbe6917136c9c674b9f5e09c76edf MD5 | raw file
  1<cffunction name="onMissingMethod" returntype="any" access="public" output="false" hint="This method handles dynamic finders, properties, and association methods. It is not part of the public API.">
  2	<cfargument name="missingMethodName" type="string" required="true" hint="Name of method attempted to load.">
  3	<cfargument name="missingMethodArguments" type="struct" required="true" hint="Name/value pairs of arguments that were passed to the attempted method call.">
  4	<cfscript>
  5		var loc = {};
  6		if (Right(arguments.missingMethodName, 10) == "hasChanged" && StructKeyExists(variables.wheels.class.properties,ReplaceNoCase(arguments.missingMethodName, "hasChanged", "")))
  7			loc.returnValue = hasChanged(property=ReplaceNoCase(arguments.missingMethodName, "hasChanged", ""));
  8		else if (Right(arguments.missingMethodName, 11) == "changedFrom" && StructKeyExists(variables.wheels.class.properties, ReplaceNoCase(arguments.missingMethodName, "changedFrom", "")))
  9			loc.returnValue = changedFrom(property=ReplaceNoCase(arguments.missingMethodName, "changedFrom", ""));
 10		else if (Right(arguments.missingMethodName, 9) == "IsPresent" && StructKeyExists(variables.wheels.class.properties, ReplaceNoCase(arguments.missingMethodName, "IsPresent", "")))
 11			loc.returnValue = propertyIsPresent(property=ReplaceNoCase(arguments.missingMethodName, "IsPresent", ""));
 12		else if (Left(arguments.missingMethodName, 9) == "columnFor" && StructKeyExists(variables.wheels.class.properties, ReplaceNoCase(arguments.missingMethodName, "columnFor", "")))
 13			loc.returnValue = columnForProperty(property=ReplaceNoCase(arguments.missingMethodName, "columnFor", ""));
 14		else if (Left(arguments.missingMethodName, 6) == "toggle" && StructKeyExists(variables.wheels.class.properties, ReplaceNoCase(arguments.missingMethodName, "toggle", "")))
 15			loc.returnValue = toggle(property=ReplaceNoCase(arguments.missingMethodName, "toggle", ""), argumentCollection=arguments.missingMethodArguments);
 16		else if (Left(arguments.missingMethodName, 3) == "has" && StructKeyExists(variables.wheels.class.properties, ReplaceNoCase(arguments.missingMethodName, "has", "")))
 17			loc.returnValue = hasProperty(property=ReplaceNoCase(arguments.missingMethodName, "has", ""));
 18		else if (Left(arguments.missingMethodName, 6) == "update" && StructKeyExists(variables.wheels.class.properties, ReplaceNoCase(arguments.missingMethodName, "update", "")))
 19		{
 20			if (!StructKeyExists(arguments.missingMethodArguments, "value"))
 21				$throw(type="Wheels.IncorrectArguments", message="The `value` argument is required but was not passed in.", extendedInfo="Pass in a value to the dynamic updateProperty in the `value` argument.");
 22			loc.returnValue = updateProperty(property=ReplaceNoCase(arguments.missingMethodName, "update", ""), value=arguments.missingMethodArguments.value);
 23		}
 24		else if (Left(arguments.missingMethodName, 9) == "findOneBy" || Left(arguments.missingMethodName, 9) == "findAllBy")
 25		{
 26			if (StructKeyExists(server, "railo"))
 27				loc.finderProperties = ListToArray(LCase(ReplaceNoCase(ReplaceNoCase(ReplaceNoCase(arguments.missingMethodName, "And", "|"), "findAllBy", ""), "findOneBy", "")), "|"); // since Railo passes in the method name in all upper case we have to do this here
 28			else
 29				loc.finderProperties = ListToArray(ReplaceNoCase(ReplaceNoCase(Replace(arguments.missingMethodName, "And", "|"), "findAllBy", ""), "findOneBy", ""), "|");
 30			loc.firstProperty = loc.finderProperties[1];
 31			loc.secondProperty = IIf(ArrayLen(loc.finderProperties) == 2, "loc.finderProperties[2]", "");
 32
 33			// throw an error when more than one argument is passed in but not `value` (for single property) or `values` (for multiple properties)
 34			// this means that model("artist").findOneByName("U2") will still work but not model("artist").findOneByName(values="U2", returnAs="query"), need to pass in just `value` there instead.
 35			if (application.wheels.showErrorInformation)
 36			{
 37				if (StructCount(arguments.missingMethodArguments) gt 1)
 38				{
 39					if (Len(loc.secondProperty))
 40					{
 41						if (!StructKeyExists(arguments.missingMethodArguments, "values"))
 42							$throw(type="Wheels.IncorrectArguments", message="The `values` argument is required but was not passed in.", extendedInfo="Pass in a list of values to the dynamic finder in the `values` argument.");
 43					}
 44					else
 45					{
 46						if (!StructKeyExists(arguments.missingMethodArguments, "value"))
 47							$throw(type="Wheels.IncorrectArguments", message="The `value` argument is required but was not passed in.", extendedInfo="Pass in a value to the dynamic finder in the `value` argument.");
 48					}
 49				}
 50			}
 51
 52			if (StructCount(arguments.missingMethodArguments) == 1)
 53				loc.firstValue = Trim(ListFirst(arguments.missingMethodArguments[1]));
 54			else if (StructKeyExists(arguments.missingMethodArguments, "value"))
 55				loc.firstValue = arguments.missingMethodArguments.value;
 56			else if (StructKeyExists(arguments.missingMethodArguments, "values"))
 57				loc.firstValue = Trim(ListFirst(arguments.missingMethodArguments.values));
 58			loc.addToWhere = loc.firstProperty & " " & $dynamicFinderOperator(loc.firstProperty) & " '" & loc.firstValue & "'";
 59			if (Len(loc.secondProperty))
 60			{
 61				if (StructCount(arguments.missingMethodArguments) == 1)
 62					loc.secondValue = Trim(ListLast(arguments.missingMethodArguments[1]));
 63				else if (StructKeyExists(arguments.missingMethodArguments, "values"))
 64					loc.secondValue = Trim(ListLast(arguments.missingMethodArguments.values));
 65				loc.addToWhere = loc.addToWhere & " AND " & loc.secondProperty & " " & $dynamicFinderOperator(loc.secondProperty) & " '" & loc.secondValue & "'";
 66			}
 67			arguments.missingMethodArguments.where = IIf(StructKeyExists(arguments.missingMethodArguments, "where"), "'(' & arguments.missingMethodArguments.where & ') AND (' & loc.addToWhere & ')'", "loc.addToWhere");
 68			StructDelete(arguments.missingMethodArguments, "1");
 69			StructDelete(arguments.missingMethodArguments, "value");
 70			StructDelete(arguments.missingMethodArguments, "values");
 71			loc.returnValue = IIf(Left(arguments.missingMethodName, 9) == "findOneBy", "findOne(argumentCollection=arguments.missingMethodArguments)", "findAll(argumentCollection=arguments.missingMethodArguments)");
 72		}
 73		else
 74		{
 75			loc.returnValue = $associationMethod(argumentCollection=arguments);
 76		}
 77		if (!StructKeyExists(loc, "returnValue"))
 78			$throw(type="Wheels.MethodNotFound", message="The method `#arguments.missingMethodName#` was not found in the `#variables.wheels.class.modelName#` model.", extendedInfo="Check your spelling or add the method to the model's CFC file.");
 79	</cfscript>
 80	<cfreturn loc.returnValue>
 81</cffunction>
 82
 83<cffunction name="$dynamicFinderOperator" returntype="string" access="public" output="false">
 84	<cfargument name="property" type="string" required="true">
 85	<cfscript>
 86		if (StructKeyExists(variables.wheels.class.properties, arguments.property) && variables.wheels.class.properties[arguments.property].dataType == "text")
 87			return "LIKE";
 88		else
 89			return "=";
 90	</cfscript>
 91</cffunction>
 92
 93<cffunction name="$associationMethod" returntype="any" access="public" output="false">
 94	<cfscript>
 95		var loc = {};
 96		for (loc.key in variables.wheels.class.associations)
 97		{
 98			loc.method = "";
 99			if (StructKeyExists(variables.wheels.class.associations[loc.key], "shortcut") && arguments.missingMethodName == variables.wheels.class.associations[loc.key].shortcut)
100			{
101				loc.method = "findAll";
102				loc.joinAssociation = $expandedAssociations(include=loc.key);
103				loc.joinAssociation = loc.joinAssociation[1];
104				loc.joinClass = loc.joinAssociation.modelName;
105				loc.info = model(loc.joinClass).$expandedAssociations(include=ListFirst(variables.wheels.class.associations[loc.key].through));
106				loc.info = loc.info[1];
107				loc.componentReference = model(loc.info.modelName);
108				loc.include = ListLast(variables.wheels.class.associations[loc.key].through);
109				if (StructKeyExists(arguments.missingMethodArguments, "include"))
110					loc.include = "#loc.include#(#arguments.missingMethodArguments.include#)";
111				arguments.missingMethodArguments.include = loc.include;
112				loc.where = $keyWhereString(properties=loc.joinAssociation.foreignKey, keys=loc.componentReference.primaryKeys());
113				if (StructKeyExists(arguments.missingMethodArguments, "where"))
114					loc.where = "(#loc.where#) AND (#arguments.missingMethodArguments.where#)";
115				arguments.missingMethodArguments.where = loc.where;
116				if (!StructKeyExists(arguments.missingMethodArguments, "returnIncluded"))
117					arguments.missingMethodArguments.returnIncluded = false;
118			}
119			else if (ListFindNoCase(variables.wheels.class.associations[loc.key].methods, arguments.missingMethodName))
120			{
121				loc.info = $expandedAssociations(include=loc.key);
122				loc.info = loc.info[1];
123				loc.componentReference = model(loc.info.modelName);
124				if (loc.info.type == "hasOne")
125				{
126					loc.where = $keyWhereString(properties=loc.info.foreignKey, keys=primaryKeys());
127					if (StructKeyExists(arguments.missingMethodArguments, "where"))
128						loc.where = "(#loc.where#) AND (#arguments.missingMethodArguments.where#)";
129					loc.name = ReplaceNoCase(arguments.missingMethodName, loc.key, "object"); // create a generic method name (example: "hasProfile" becomes "hasObject")
130					if (loc.name == "object")
131					{
132						loc.method = "findOne";
133						arguments.missingMethodArguments.where = loc.where;
134					}
135					else if (loc.name == "hasObject")
136					{
137						loc.method = "exists";
138						arguments.missingMethodArguments.where = loc.where;
139					}
140					else if (loc.name == "newObject")
141					{
142						loc.method = "new";
143						$setForeignKeyValues(missingMethodArguments=arguments.missingMethodArguments, keys=loc.info.foreignKey);
144					}
145					else if (loc.name == "createObject")
146					{
147						loc.method = "create";
148						$setForeignKeyValues(missingMethodArguments=arguments.missingMethodArguments, keys=loc.info.foreignKey);
149					}
150					else if (loc.name == "removeObject")
151					{
152						loc.method = "updateOne";
153						arguments.missingMethodArguments.where = loc.where;
154						$setForeignKeyValues(missingMethodArguments=arguments.missingMethodArguments, keys=loc.info.foreignKey, setToNull=true);
155					}
156					else if (loc.name == "deleteObject")
157					{
158						loc.method = "deleteOne";
159						arguments.missingMethodArguments.where = loc.where;
160					}
161					else if (loc.name == "setObject")
162					{
163						// single argument, must be either the key or the object
164						if (StructCount(arguments.missingMethodArguments) eq 1)
165						{
166							if (IsObject(arguments.missingMethodArguments[1]))
167							{
168								loc.componentReference = arguments.missingMethodArguments[1];
169								loc.method = "update";
170							}
171							else
172							{
173								arguments.missingMethodArguments.key = arguments.missingMethodArguments[1];
174								loc.method = "updateByKey";
175							}
176							StructDelete(arguments.missingMethodArguments, "1");
177						}
178						// multiple arguments so ensure that either 'key' or the association name exists (loc.key)
179						else
180						{
181							if (StructKeyExists(arguments.missingMethodArguments, loc.key) and IsObject(arguments.missingMethodArguments[loc.key]))
182							{
183								loc.componentReference = arguments.missingMethodArguments[loc.key];
184								loc.method = "update";
185								StructDelete(arguments.missingMethodArguments, loc.key);
186							}
187							else if (StructKeyExists(arguments.missingMethodArguments, "key"))
188								loc.method = "updateByKey";
189							else
190								$throw(type="Wheels.IncorrectArguments", message="The `#loc.key#` or `key` named argument is required.", extendedInfo="When using multiple arguments for #loc.name#() you must supply an object using the argument `#loc.key#` or a key using the argument `key`, e.g. #loc.name#(#loc.key#=post) or #loc.name#(key=post.id).");
191						}
192						$setForeignKeyValues(missingMethodArguments=arguments.missingMethodArguments, keys=loc.info.foreignKey);
193					}
194				}
195				else if (loc.info.type == "hasMany")
196				{
197					loc.where = $keyWhereString(properties=loc.info.foreignKey, keys=primaryKeys());
198					if (StructKeyExists(arguments.missingMethodArguments, "where"))
199						loc.where = "(#loc.where#) AND (#arguments.missingMethodArguments.where#)";
200					loc.singularKey = singularize(loc.key);
201					loc.name = ReplaceNoCase(ReplaceNoCase(arguments.missingMethodName, loc.key, "objects"), loc.singularKey, "object"); // create a generic method name (example: "hasComments" becomes "hasObjects")
202					if (loc.name == "objects")
203					{
204						loc.method = "findAll";
205						arguments.missingMethodArguments.where = loc.where;
206					}
207					else if (loc.name == "addObject")
208					{
209						// single argument, must be either the key or the object
210						if (StructCount(arguments.missingMethodArguments) eq 1)
211						{
212							if (IsObject(arguments.missingMethodArguments[1]))
213							{
214								loc.componentReference = arguments.missingMethodArguments[1];
215								loc.method = "update";
216							}
217							else
218							{
219								arguments.missingMethodArguments.key = arguments.missingMethodArguments[1];
220								loc.method = "updateByKey";
221							}
222							StructDelete(arguments.missingMethodArguments, "1");
223						}
224						// multiple arguments so ensure that either 'key' or the singularized association name exists (loc.singularKey)
225						else
226						{
227							if (StructKeyExists(arguments.missingMethodArguments, loc.singularKey) and IsObject(arguments.missingMethodArguments[loc.singularKey]))
228							{
229								loc.componentReference = arguments.missingMethodArguments[loc.singularKey];
230								loc.method = "update";
231								StructDelete(arguments.missingMethodArguments, loc.singularKey);
232							}
233							else if (StructKeyExists(arguments.missingMethodArguments, "key"))
234								loc.method = "updateByKey";
235							else
236								$throw(type="Wheels.IncorrectArguments", message="The `#loc.singularKey#` or `key` named argument is required.", extendedInfo="When using multiple arguments for #loc.name#() you must supply an object using the argument `#loc.singularKey#` or a key using the argument `key`, e.g. #loc.name#(#loc.singularKey#=post) or #loc.name#(key=post.id).");
237						}
238						$setForeignKeyValues(missingMethodArguments=arguments.missingMethodArguments, keys=loc.info.foreignKey);
239					}
240					else if (loc.name == "removeObject")
241					{
242						// single argument, must be either the key or the object
243						if (StructCount(arguments.missingMethodArguments) eq 1)
244						{
245							if (IsObject(arguments.missingMethodArguments[1]))
246							{
247								loc.componentReference = arguments.missingMethodArguments[1];
248								loc.method = "update";
249							}
250							else
251							{
252								arguments.missingMethodArguments.key = arguments.missingMethodArguments[1];
253								loc.method = "updateByKey";
254							}
255							StructDelete(arguments.missingMethodArguments, "1");
256						}
257						// multiple arguments so ensure that either 'key' or the singularized object name exists (loc.singularKey)
258						else
259						{
260							if (StructKeyExists(arguments.missingMethodArguments, loc.singularKey) and IsObject(arguments.missingMethodArguments[loc.singularKey]))
261							{
262								loc.componentReference = arguments.missingMethodArguments[loc.singularKey];
263								loc.method = "update";
264								StructDelete(arguments.missingMethodArguments, loc.singularKey);
265							}
266							else if (StructKeyExists(arguments.missingMethodArguments, "key"))
267								loc.method = "updateByKey";
268							else
269								$throw(type="Wheels.IncorrectArguments", message="The `#loc.singularKey#` or `key` named argument is required.", extendedInfo="When using multiple arguments for #loc.name#() you must supply an object using the argument `#loc.singularKey#` or a key using the argument `key`, e.g. #loc.name#(#loc.singularKey#=post) or #loc.name#(key=post.id).");
270						}
271						$setForeignKeyValues(missingMethodArguments=arguments.missingMethodArguments, keys=loc.info.foreignKey, setToNull=true);
272					}
273					else if (loc.name == "deleteObject")
274					{
275						// single argument, must be either the key or the object
276						if (StructCount(arguments.missingMethodArguments) eq 1)
277						{
278							if (IsObject(arguments.missingMethodArguments[1]))
279							{
280								loc.componentReference = arguments.missingMethodArguments[1];
281								loc.method = "delete";
282							}
283							else
284							{
285								arguments.missingMethodArguments.key = arguments.missingMethodArguments[1];
286								loc.method = "deleteByKey";
287							}
288							StructDelete(arguments.missingMethodArguments, "1");
289						}
290						// multiple arguments so ensure that either 'key' or the singularized object name exists (loc.singularKey)
291						else
292						{
293							if (StructKeyExists(arguments.missingMethodArguments, loc.singularKey) and IsObject(arguments.missingMethodArguments[loc.singularKey]))
294							{
295								loc.componentReference = arguments.missingMethodArguments[loc.singularKey];
296								loc.method = "delete";
297								StructDelete(arguments.missingMethodArguments, loc.singularKey);
298							}
299							else if (StructKeyExists(arguments.missingMethodArguments, "key"))
300								loc.method = "deleteByKey";
301							else
302								$throw(type="Wheels.IncorrectArguments", message="The `#loc.singularKey#` or `key` named argument is required.", extendedInfo="When using multiple arguments for #loc.name#() you must supply an object using the argument `#loc.singularKey#` or a key using the argument `key`, e.g. #loc.name#(#loc.singularKey#=post) or #loc.name#(key=post.id).");
303						}
304						$setForeignKeyValues(missingMethodArguments=arguments.missingMethodArguments, keys=loc.info.foreignKey);
305					}
306					else if (loc.name == "hasObjects")
307					{
308						loc.method = "exists";
309						arguments.missingMethodArguments.where = loc.where;
310					}
311					else if (loc.name == "newObject")
312					{
313						loc.method = "new";
314						$setForeignKeyValues(missingMethodArguments=arguments.missingMethodArguments, keys=loc.info.foreignKey);
315					}
316					else if (loc.name == "createObject")
317					{
318						loc.method = "create";
319						$setForeignKeyValues(missingMethodArguments=arguments.missingMethodArguments, keys=loc.info.foreignKey);
320					}
321					else if (loc.name == "objectCount")
322					{
323						loc.method = "count";
324						arguments.missingMethodArguments.where = loc.where;
325					}
326					else if (loc.name == "findOneObject")
327					{
328						loc.method = "findOne";
329						arguments.missingMethodArguments.where = loc.where;
330					}
331					else if (loc.name == "removeAllObjects")
332					{
333						loc.method = "updateAll";
334						arguments.missingMethodArguments.where = loc.where;
335						$setForeignKeyValues(missingMethodArguments=arguments.missingMethodArguments, keys=loc.info.foreignKey, setToNull=true);
336					}
337					else if (loc.name == "deleteAllObjects")
338					{
339						loc.method = "deleteAll";
340						arguments.missingMethodArguments.where = loc.where;
341					}
342				}
343				else if (loc.info.type == "belongsTo")
344				{
345					loc.where = $keyWhereString(keys=loc.info.foreignKey, properties=loc.componentReference.primaryKeys());
346					if (StructKeyExists(arguments.missingMethodArguments, "where"))
347						loc.where = "(#loc.where#) AND (#arguments.missingMethodArguments.where#)";
348					loc.name = ReplaceNoCase(arguments.missingMethodName, loc.key, "object"); // create a generic method name (example: "hasAuthor" becomes "hasObject")
349					if (loc.name == "object")
350					{
351						loc.method = "findByKey";
352						arguments.missingMethodArguments.key = $propertyValue(name=loc.info.foreignKey);
353					}
354					else if (loc.name == "hasObject")
355					{
356						loc.method = "exists";
357						arguments.missingMethodArguments.key = $propertyValue(name=loc.info.foreignKey);
358					}
359				}
360			}
361			if (Len(loc.method))
362				loc.returnValue = $invoke(componentReference=loc.componentReference, method=loc.method, invokeArgs=arguments.missingMethodArguments);
363		}
364	</cfscript>
365	<cfif StructKeyExists(loc, "returnValue")>
366		<cfreturn loc.returnValue>
367	</cfif>
368</cffunction>
369
370<cffunction name="$propertyValue" returntype="string" access="public" output="false" hint="Returns the object's value of the passed in property name. If you pass in a list of property names you will get the values back in a list as well.">
371	<cfargument name="name" type="string" required="true" hint="Name of property to get value for.">
372	<cfscript>
373		var loc = {};
374		loc.returnValue = "";
375		loc.iEnd = ListLen(arguments.name);
376		for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
377			loc.returnValue = ListAppend(loc.returnValue, this[ListGetAt(arguments.name, loc.i)]);
378	</cfscript>
379	<cfreturn loc.returnValue>
380</cffunction>
381
382<cffunction name="$setForeignKeyValues" returntype="void" access="public" output="false">
383	<cfargument name="missingMethodArguments" type="struct" required="true">
384	<cfargument name="keys" type="string" required="true">
385	<cfargument name="setToNull" type="boolean" required="false" default="false">
386	<cfscript>
387		var loc = {};
388		loc.iEnd = ListLen(arguments.keys);
389		for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
390		{
391			if (arguments.setToNull)
392				arguments.missingMethodArguments[ListGetAt(arguments.keys, loc.i)] = "";
393			else
394				arguments.missingMethodArguments[ListGetAt(arguments.keys, loc.i)] = this[primaryKeys(loc.i)];
395		}
396	</cfscript>
397</cffunction>