PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/wheels/model/miscellaneous.cfm

http://cfwheels.googlecode.com/
ColdFusion | 406 lines | 318 code | 37 blank | 51 comment | 19 complexity | 8cbe20494595ec18b0e2046e27c5ccfd MD5 | raw file
Possible License(s): Apache-2.0, CPL-1.0
  1. <!--- PUBLIC MODEL INITIALIZATION METHODS --->
  2. <cffunction name="dataSource" returntype="void" access="public" output="false" hint="Use this method to override the data source connection information for this model."
  3. examples=
  4. '
  5. <!--- In models/User.cfc --->
  6. <cffunction name="init">
  7. <!--- Tell Wheels to use the data source named `users_source` instead of the default one whenever this model makes SQL calls --->
  8. <cfset dataSource("users_source")>
  9. </cffunction>
  10. '
  11. categories="model-initialization,miscellaneous" chapters="using-multiple-data-sources" functions="">
  12. <cfargument name="datasource" type="string" required="true" hint="The data source name to connect to.">
  13. <cfargument name="username" type="string" required="false" default="" hint="The username for the data source.">
  14. <cfargument name="password" type="string" required="false" default="" hint="The password for the data source.">
  15. <cfscript>
  16. StructAppend(variables.wheels.class.connection, arguments, true);
  17. </cfscript>
  18. </cffunction>
  19. <cffunction name="getDataSource" returntype="struct" access="public" output="false" hint="returns the connection (datasource) information for the model."
  20. examples=
  21. '
  22. <!--- get the datasource information so we can write custom queries --->
  23. <cfquery name="q" datasource="##getDataSource().datasource##">
  24. select * from mytable
  25. </cfquery>
  26. '>
  27. <cfreturn variables.wheels.class.connection>
  28. </cffunction>
  29. <cffunction name="table" returntype="void" access="public" output="false" hint="Use this method to tell Wheels what database table to connect to for this model. You only need to use this method when your table naming does not follow the standard Wheels convention of a singular object name mapping to a plural table name."
  30. examples=
  31. '
  32. <!--- In models/User.cfc --->
  33. <cffunction name="init">
  34. <!--- Tell Wheels to use the `tbl_USERS` table in the database for the `user` model instead of the default (which would be `users`) --->
  35. <cfset table("tbl_USERS")>
  36. </cffunction>
  37. '
  38. categories="model-initialization,miscellaneous" chapters="object-relational-mapping" functions="columnNames,dataSource,property,propertyNames,tableName">
  39. <cfargument name="name" type="string" required="true" hint="Name of the table to map this model to.">
  40. <cfset variables.wheels.class.tableName = arguments.name>
  41. </cffunction>
  42. <cffunction name="setTableNamePrefix" returntype="void" access="public" output="false" hint="Sets a prefix to prepend to the table name when this model runs SQL queries."
  43. examples='
  44. <!--- In `models/User.cfc`, add a prefix to the default table name of `tbl` --->
  45. <cffunction name="init">
  46. <cfset setTableNamePrefix("tbl")>
  47. </cffunction>
  48. '
  49. categories="model-initialization,miscellaneous" chapters="object-relational-mapping" functions="columnNames,dataSource,property,propertyNames,table">
  50. <cfargument name="prefix" type="string" required="true" hint="A prefix to prepend to the table name.">
  51. <cfset variables.wheels.class.tableNamePrefix = arguments.prefix>
  52. </cffunction>
  53. <cffunction name="setPrimaryKey" returntype="void" access="public" output="false" hint="Allows you to pass in the name(s) of the property(s) that should be used as the primary key(s). Pass as a list if defining a composite primary key. Also aliased as `setPrimaryKeys()`."
  54. examples='
  55. <!--- In `models/User.cfc`, define the primary key as a column called `userID` --->
  56. <cffunction name="init">
  57. <cfset setPrimaryKey("userID")>
  58. </cffunction>
  59. '
  60. categories="model-initialization,miscellaneous" chapters="object-relational-mapping" functions="columnNames,dataSource,property,propertyNames,table">
  61. <cfargument name="property" type="string" required="true" hint="Property (or list of properties) to set as the primary key.">
  62. <cfset var loc = {}>
  63. <cfloop list="#arguments.property#" index="loc.i">
  64. <cfset variables.wheels.class.keys = ListAppend(variables.wheels.class.keys, loc.i)>
  65. </cfloop>
  66. </cffunction>
  67. <cffunction name="setPrimaryKeys" returntype="void" access="public" output="false" hint="Alias for @setPrimaryKey. Use this for better readability when you're setting multiple properties as the primary key."
  68. examples='
  69. <!--- In `models/Subscription.cfc`, define the primary key as composite of the columns `customerId` and `publicationId` --->
  70. <cffunction name="init">
  71. <cfset setPrimaryKeys("customerId,publicationId")>
  72. </cffunction>
  73. '
  74. categories="model-initialization,miscellaneous" chapters="object-relational-mapping" functions="columnNames,dataSource,property,propertyNames,table">
  75. <cfargument name="property" type="string" required="true" hint="Property (or list of properties) to set as the primary key.">
  76. <cfset setPrimaryKey(argumentCollection=arguments)>
  77. </cffunction>
  78. <!--- PUBLIC MODEL CLASS METHODS --->
  79. <cffunction name="columnNames" returntype="string" access="public" output="false" hint="Returns a list of column names in the table mapped to this model. The list is ordered according to the columns' ordinal positions in the database table."
  80. examples=
  81. '
  82. <!--- Get a list of all the column names in the table mapped to the `author` model --->
  83. <cfset columns = model("author").columnNames()>
  84. '
  85. categories="model-class,miscellaneous" chapters="object-relational-mapping" functions="dataSource,property,propertyNames,table,tableName">
  86. <cfreturn variables.wheels.class.columnList>
  87. </cffunction>
  88. <cffunction name="primaryKey" returntype="string" access="public" output="false" hint="Returns the name of the primary key for this model's table. This is determined through database introspection. If composite primary keys have been used, they will both be returned in a list. This function is also aliased as `primaryKeys()`."
  89. examples=
  90. '
  91. <!--- Get the name of the primary key of the table mapped to the `employee` model (which is the `employees` table by default) --->
  92. <cfset keyName = model("employee").primaryKey()>
  93. '
  94. categories="model-class,miscellaneous" chapters="object-relational-mapping" functions="primaryKeys">
  95. <cfargument name="position" type="numeric" required="false" default="0" hint="If you are accessing a composite primary key, pass the position of a single key to fetch.">
  96. <cfif arguments.position gt 0>
  97. <cfreturn ListGetAt(variables.wheels.class.keys, arguments.position)>
  98. </cfif>
  99. <cfreturn variables.wheels.class.keys>
  100. </cffunction>
  101. <cffunction name="primaryKeys" returntype="string" access="public" output="false" hint="Alias for @primaryKey. Use this for better readability when you're accessing multiple primary keys."
  102. examples=
  103. '
  104. <!--- Get a list of the names of the primary keys in the table mapped to the `employee` model (which is the `employees` table by default) --->
  105. <cfset keyNames = model("employee").primaryKeys()>
  106. '
  107. categories="model-class,miscellaneous" chapters="object-relational-mapping" functions="primaryKey"
  108. >
  109. <cfargument name="position" type="numeric" required="false" default="0" hint="See documentation for @primaryKey.">
  110. <cfreturn primaryKey(argumentCollection=arguments)>
  111. </cffunction>
  112. <cffunction name="tableName" returntype="string" access="public" output="false" hint="Returns the name of the database table that this model is mapped to."
  113. examples=
  114. '
  115. <!--- Check what table the user model uses --->
  116. <cfset whatAmIMappedTo = model("user").tableName()>
  117. '
  118. categories="model-class,miscellaneous" chapters="object-relational-mapping" functions="columnNames,dataSource,property,propertyNames,table">
  119. <cfreturn variables.wheels.class.tableName>
  120. </cffunction>
  121. <cffunction name="getTableNamePrefix" returntype="string" access="public" output="false" hint="Returns the table name prefix set for the table."
  122. examples='
  123. <!--- Get the table name prefix for this user when running a custom query --->
  124. <cffunction name="getDisabledUsers" returntype="query">
  125. <cfset var loc = {}>
  126. <cfquery datasource="##get(''dataSourceName'')##" name="loc.disabledUsers">
  127. SELECT
  128. *
  129. FROM
  130. ##this.getTableNamePrefix()##users
  131. WHERE
  132. disabled = 1
  133. </cfquery>
  134. <cfreturn loc.disabledUsers>
  135. </cffunction>
  136. '
  137. categories="model-class,miscellaneous" chapters="object-relational-mapping" functions="columnNames,dataSource,property,propertyNames,table">
  138. <cfreturn variables.wheels.class.tableNamePrefix>
  139. </cffunction>
  140. <!--- PUBLIC MODEL OBJECT METHODS --->
  141. <cffunction name="compareTo" access="public" output="false" returntype="boolean" hint="Pass in another Wheels model object to see if the two objects are the same."
  142. examples='
  143. <!--- Load a user requested in the URL/form and restrict access if it doesn''t match the user stored in the session --->
  144. <cfset user = model("user").findByKey(params.key)>
  145. <cfif not user.compareTo(session.user)>
  146. <cfset renderPage(action="accessDenied")>
  147. </cfif>
  148. '
  149. categories="model-object,miscellaneous" chapters="" functions="">
  150. <cfargument name="object" type="component" required="true">
  151. <cfreturn Compare(this.$objectId(), arguments.object.$objectId()) eq 0 />
  152. </cffunction>
  153. <cffunction name="$objectId" access="public" output="false" returntype="string">
  154. <cfreturn variables.wheels.instance.tickCountId />
  155. </cffunction>
  156. <cffunction name="$alias" access="public" output="false" returntype="void">
  157. <cfargument name="associationName" type="string" required="true">
  158. <cfset variables.wheels.class.aliases[arguments.associationName] = tableName() & StructCount(variables.wheels.class.aliases)>
  159. </cffunction>
  160. <cffunction name="$aliasName" access="public" output="false" returntype="string">
  161. <cfargument name="associationName" type="string" required="false" default="">
  162. <cfscript>
  163. if (!Len(arguments.associationName) or !StructKeyExists(variables.wheels.class.aliases, arguments.associationName))
  164. return tableName();
  165. </cfscript>
  166. <cfreturn variables.wheels.class.aliases[arguments.associationName]>
  167. </cffunction>
  168. <cffunction name="isInstance" returntype="boolean" access="public" output="false" hint="Use this method to check whether you are currently in an instance object."
  169. examples='
  170. <!--- Use the passed in `id` when we''re not already in an instance --->
  171. <cffunction name="memberIsAdmin">
  172. <cfif isInstance()>
  173. <cfreturn this.admin>
  174. <cfelse>
  175. <cfreturn this.findByKey(arguments.id).admin>
  176. </cfif>
  177. </cffunction>
  178. '
  179. categories="model-initialization,miscellaneous" chapters="object-relational-mapping" functions="isClass">
  180. <cfreturn StructKeyExists(variables.wheels, "instance")>
  181. </cffunction>
  182. <cffunction name="isClass" returntype="boolean" access="public" output="false" hint="Use this method within a model's method to check whether you are currently in a class-level object."
  183. examples='
  184. <!--- Use the passed in `id` when we''re already in an instance --->
  185. <cffunction name="memberIsAdmin">
  186. <cfif isClass()>
  187. <cfreturn this.findByKey(arguments.id).admin>
  188. <cfelse>
  189. <cfreturn this.admin>
  190. </cfif>
  191. </cffunction>
  192. '
  193. categories="model-initialization,miscellaneous" chapters="object-relational-mapping" functions="isInstance">
  194. <cfreturn !isInstance(argumentCollection=arguments)>
  195. </cffunction>
  196. <cffunction name="setPagination" access="public" output="false" returntype="void" hint="Allows you to set a pagination handle for a custom query so you can perform pagination on it in your view with `paginationLinks()`."
  197. examples=
  198. '
  199. <!---
  200. Note that there are two ways to do pagination yourself using
  201. a custom query.
  202. 1) Do a query that grabs everything that matches and then use
  203. the `cfouput` or `cfloop` tag to page through the results.
  204. 2) Use your database to make 2 queries. The first query
  205. basically does a count of the total number of records that match
  206. the criteria and the second query actually selects the page of
  207. records for retrieval.
  208. In the example below, we will show how to write a custom query
  209. using both of these methods. Note that the syntax where your
  210. database performs the pagination will differ depending on the
  211. database engine you are using. Plese consult your database
  212. engine''s documentation for the correct syntax.
  213. Also note that the view code will differ depending on the method
  214. used.
  215. --->
  216. <!---
  217. First method: Handle the pagination through your CFML engine
  218. --->
  219. <!--- Model code --->
  220. <!--- In your model (ie. User.cfc), create a custom method for your custom query --->
  221. <cffunction name="myCustomQuery">
  222. <cfargument name="page" type="numeric">
  223. <cfargument name="perPage" type="numeric" required="false" default="25">
  224. <cfquery name="local.customQuery" datasource="##get(''dataSourceName'')##">
  225. SELECT * FROM users
  226. </cfquery>
  227. <cfset setPagination(totalRecords=local.customQuery.RecordCount, currentPage=arguments.page, perPage=arguments.perPage, handle="myCustomQueryHandle")>
  228. <cfreturn customQuery>
  229. </cffunction>
  230. <!--- Controller code --->
  231. <cffunction name="list">
  232. <cfparam name="params.page" default="1">
  233. <cfparam name="params.perPage" default="25">
  234. <cfset allUsers = model("user").myCustomQuery(page=params.page, perPage=params.perPage)>
  235. <!---
  236. Because we''re going to let `cfoutput`/`cfloop` handle the pagination,
  237. we''re going to need to get some addition information about the
  238. pagination.
  239. --->
  240. <cfset paginationData = pagination("myCustomQueryHandle")>
  241. </cffunction>
  242. <!--- View code (using `cfloop`) --->
  243. <!--- Use the information from `paginationData` to page through the records --->
  244. <cfoutput>
  245. <ul>
  246. <cfloop query="allUsers" statrow="##paginationData.startrow##" endrow="##paginationData.endrow##">
  247. <li>##allUsers.firstName## ##allUsers.lastName##</li>
  248. </cfloop>
  249. </ul>
  250. ##paginationLinks(handle="myCustomQueryHandle")##
  251. </cfoutput>
  252. <!--- View code (using `cfoutput`) --->
  253. <!--- Use the information from `paginationData` to page through the records --->
  254. <ul>
  255. <cfoutput query="allUsers" statrow="##paginationData.startrow##" maxrows="##paginationData.maxrows##">
  256. <li>##allUsers.firstName## ##allUsers.lastName##</li>
  257. </cfoutput>
  258. </ul>
  259. <cfoutput>##paginationLinks(handle="myCustomQueryHandle")##</cfoutput>
  260. <!---
  261. Second method: Handle the pagination through the database
  262. --->
  263. <!--- Model code --->
  264. <!--- In your model (ie. `User.cfc`), create a custom method for your custom query --->
  265. <cffunction name="myCustomQuery">
  266. <cfargument name="page" type="numeric">
  267. <cfargument name="perPage" type="numeric" required="false" default="25">
  268. <cfquery name="local.customQueryCount" datasource="##get(''dataSouceName'')##">
  269. SELECT COUNT(*) AS theCount FROM users
  270. </cfquery>
  271. <cfquery name="local.customQuery" datasource="##get(''dataSourceName'')##">
  272. SELECT * FROM users
  273. LIMIT ##arguments.page## OFFSET ##arguments.perPage##
  274. </cfquery>
  275. <!--- Notice the we use the value from the first query for `totalRecords` --->
  276. <cfset setPagination(totalRecords=local.customQueryCount.theCount, currentPage=arguments.page, perPage=arguments.perPage, handle="myCustomQueryHandle")>
  277. <!--- We return the second query --->
  278. <cfreturn customQuery>
  279. </cffunction>
  280. <!--- Controller code --->
  281. <cffunction name="list">
  282. <cfparam name="params.page" default="1">
  283. <cfparam name="params.perPage" default="25">
  284. <cfset allUsers = model("user").myCustomQuery(page=params.page, perPage=params.perPage)>
  285. </cffunction>
  286. <!--- View code (using `cfloop`) --->
  287. <cfoutput>
  288. <ul>
  289. <cfloop query="allUsers">
  290. <li>##allUsers.firstName## ##allUsers.lastName##</li>
  291. </cfloop>
  292. </ul>
  293. ##paginationLinks(handle="myCustomQueryHandle")##
  294. </cfoutput>
  295. <!--- View code (using `cfoutput`) --->
  296. <ul>
  297. <cfoutput query="allUsers">
  298. <li>##allUsers.firstName## ##allUsers.lastName##</li>
  299. </cfoutput>
  300. </ul>
  301. <cfoutput>##paginationLinks(handle="myCustomQueryHandle")##</cfoutput>
  302. '
  303. categories="model-class,miscellaneous" chapters="getting-paginated-data" functions="findAll,paginationLinks">
  304. <cfargument name="totalRecords" type="numeric" required="true" hint="Total count of records that should be represented by the paginated links.">
  305. <cfargument name="currentPage" type="numeric" required="false" default="1" hint="Page number that should be represented by the data being fetched and the paginated links.">
  306. <cfargument name="perPage" type="numeric" required="false" default="25" hint="Number of records that should be represented on each page of data.">
  307. <cfargument name="handle" type="string" required="false" default="query" hint="Name of handle to reference in @paginationLinks.">
  308. <cfscript>
  309. var loc = {};
  310. // all numeric values must be integers
  311. arguments.totalRecords = fix(arguments.totalRecords);
  312. arguments.currentPage = fix(arguments.currentPage);
  313. arguments.perPage = fix(arguments.perPage);
  314. // totalRecords cannot be negative
  315. if (arguments.totalRecords lt 0)
  316. {
  317. arguments.totalRecords = 0;
  318. }
  319. // perPage less then zero
  320. if (arguments.perPage lte 0)
  321. {
  322. arguments.perPage = 25;
  323. }
  324. // calculate the total pages the query will have
  325. arguments.totalPages = Ceiling(arguments.totalRecords/arguments.perPage);
  326. // currentPage shouldn't be less then 1 or greater then the number of pages
  327. if (arguments.currentPage gte arguments.totalPages)
  328. {
  329. arguments.currentPage = arguments.totalPages;
  330. }
  331. if (arguments.currentPage lt 1)
  332. {
  333. arguments.currentPage = 1;
  334. }
  335. // as a convinence for cfquery and cfloop when doing oldschool type pagination
  336. // startrow for cfquery and cfloop
  337. arguments.startRow = (arguments.currentPage * arguments.perPage) - arguments.perPage + 1;
  338. // maxrows for cfquery
  339. arguments.maxRows = arguments.perPage;
  340. // endrow for cfloop
  341. arguments.endRow = arguments.startRow + arguments.perPage;
  342. // endRow shouldn't be greater then the totalRecords or less than startRow
  343. if (arguments.endRow gte arguments.totalRecords)
  344. {
  345. arguments.endRow = arguments.totalRecords;
  346. }
  347. if (arguments.endRow lt arguments.startRow)
  348. {
  349. arguments.endRow = arguments.startRow;
  350. }
  351. loc.args = duplicate(arguments);
  352. structDelete(loc.args, "handle", false);
  353. request.wheels[arguments.handle] = loc.args;
  354. </cfscript>
  355. </cffunction>