-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathframework.cfc
450 lines (357 loc) · 14.9 KB
/
framework.cfc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
<cfcomponent hint="2011.7.18.5.30" output="false">
<cffunction name="action" returntype="String">
<cfargument name="section" required="true" type="string">
<cfargument name="item" required="true" type="string">
<cfargument name="query" default="" type="string" hint="extra context/query-string params">
<cfset var result = ''>
<cfset result = application.URL & '?action=' & arguments.section & '.' & arguments.item>
<cfif len(arguments.query)>
<cfset result &= '&' & arguments.query>
</cfif>
<cfreturn result>
</cffunction>
<cffunction name="addView" returntype="void">
<cfargument name="section" required="true" type="string">
<cfargument name="item" required="true" type="string">
<cfset var newView = structNew()>
<cfset newView.section = arguments.section>
<cfset newView.item = arguments.item>
<cfset arrayAppend(request.view, newView)>
</cffunction>
<cffunction name="cache">
<cfargument name="section" required="true" type="string">
<cfif isDefined('application.cache.#arguments.section#')>
<cfreturn application.cache[arguments.section]>
<cfelse>
<cfthrow detail="application.cache.#arguments.section# does not exist in the cache" message="there is no section #arguments.section#">
</cfif>
</cffunction>
<cffunction name="cacheExists">
<cfargument name="section" required="true" type="string">
<cfreturn structKeyExists(application.cache, arguments.section)>
</cffunction>
<cffunction name="checkCache" returntype="void">
<cfargument name="section" required="true" type="string">
<cfif not cacheExists(arguments.section) or application.fwDefault.reloadApplicationOnEveryRequest>
<cfset setupSectionCache(arguments.section)>
</cfif>
</cffunction>
<cffunction name="context">
<cfargument name="name" required="false" type="string">
<cfargument name="value" required="false" type="any">
<cfif not isDefined('request.context')>
<cfset request.context = structNew()>
</cfif>
<cfif isDefined('arguments.value')>
<cfset request.context[arguments.name] = arguments.value>
<cfelseif isDefined('arguments.name')>
<cfif not isDefined('request.context.#arguments.name#')>
<cfreturn false>
</cfif>
<cfreturn request.context[arguments.name]>
<cfelse>
<cfreturn request.context>
</cfif>
</cffunction>
<cffunction name="dotPath" returntype="String">
<cfargument name="filePath" required="true" type="string">
<cfset var result = replaceNoCase(filePath, application.path, '')>
<cfset result = replace(result, '\', '/', "all")>
<cfset result = listDeleteAt(result, listLen(result, '.'), '.')>
<cfset result = listChangeDelims(result, '.', '/')>
<cfreturn result>
</cffunction>
<cffunction name="ignoredPath" returntype="boolean">
<cfargument name="sectionName" required="true" type="string">
<cfreturn application.fwDefault.ignoredPaths contains arguments.sectionName>
</cffunction>
<cffunction name="onApplicationStart" output="true">
<cfset application.path = getDirectoryFromPath(getBaseTemplatePath())>
<cfset application.path = replace(application.path, '\', '/', "all")>
<cfif CGI.HTTPS is 'on'>
<cfset application.URL = 'https://'>
<cfelse>
<cfset application.URL = 'http://'>
</cfif>
<cfset application.URL &= CGI.HTTP_HOST & '/'>
<cfset application.fwDefault = structNew()>
<cfset application.fwDefault.defaultSection = 'main'>
<cfset application.fwDefault.actionDelimiter = '.'>
<cfset application.fwDefault.defaultItem = 'default'>
<cfset application.fwDefault.defaultAction = application.fwDefault.defaultSection & application.fwDefault.actionDelimiter & application.fwDefault.defaultItem>
<cfset application.fwDefault.reloadApplicationOnEveryRequest = true>
<cfset application.fwDefault.reloadKey = 'restart'>
<cfset application.fwDefault.reloadVal = 'goober'>
<cfset application.fwDefault.ignoredPaths = 'tests'>
<cfif fileExists(application.path & 'layout.cfm')>
<cfset application.fwDefault.layoutPages = true>
<cfelse>
<cfset application.fwDefault.layoutPages = false>
</cfif>
<cfset application.cache = structNew()>
<cfset setupApplicationCache()>
<cfif isDefined('setupApplication') and isCustomFunction(setupApplication)>
<cfset setupApplication(fw=this)>
</cfif>
</cffunction>
<cffunction name="onApplicationEnd">
<cfargument name="applicationScope">
<cfif isDefined('teardownApplication') and isCustomFunction(teardownApplication)>
<cfset teardownApplication(fw=this)>
</cfif>
</cffunction>
<cffunction name="onError" returnType="void">
<cfargument name="Exception" required="true">
<cfargument name="EventName" type="String" required="true">
<div style="border: double red;">
<cfdump var="#arguments#">
</cffunction>
<cffunction name="onMissingTemplate" returnType="boolean">
<cfargument type="string" name="targetPage" required=true>
<cfreturn true>
</cffunction>
<cffunction name="onRequestStart" output="true" returnType="boolean">
<cfargument type="String" name="targetPage" required=true>
<cfset request.action = structNew()>
<cfset request.context = structNew()>
<cfset request.service = structNew()>
<cfset request.context = structCopy(URL)>
<cfset structAppend(request.context, structCopy(form))>
<cfparam name="request.context.action" default="#application.fwDefault.defaultAction#">
<cfset request.item = listLast(request.context.action, application.fwDefault.actionDelimiter)>
<cfset request.section = listFirst(request.context.action, application.fwDefault.actionDelimiter)>
<cfif application.fwDefault.reloadApplicationOnEveryRequest>
<cfset onApplicationStart()>
</cfif>
<cfif isDefined('request.context.#application.fwDefault.reloadKey#') and (request.context[application.fwDefault.reloadKey] is application.fwDefault.reloadVal)>
<cfset onApplicationStart()>
</cfif>
<cfif not ignoredPath(request.section)>
<cfset setupSectionCache(request.section)>
<cfset request.action = cache(request.section)>
<cfif isDefined('request.action.service')>
<cfset request.service = request.action.service>
</cfif>
<cfset request.view = arrayNew(1)>
<cfset setView(request.section, request.item)>
<cfif isDefined('setupRequest') and isCustomFunction(setupRequest)>
<cfset setupRequest(fw=this, context=request.context, service=request.service)>
</cfif>
</cfif>
<cfreturn true>
</cffunction>
<cffunction name="onRequest" output="true" returnType="void">
<cfargument name="targetPage" type="String" required=true>
<cfset var controller = ''>
<cfset var thisView = "">
<cfdump var="#request#">
<cfif ignoredPath(request.section)>
<cfinclude template="#arguments.targetPage#">
<cfelse>
<cfif isDefined('application.cache.#request.section#.before')>
<cfset beforeModule = application.cache[request.section].before>
<cfinclude template="#beforeModule#">
</cfif>
<cfif isDefined('application.setup') and isDefined('application.setup.#request.section#')>
<cfinvoke component="application.setup" method="#request.section#" fw=this context=request.context service=request.service>
</cfif>
<cfif isDefined('request.view')>
<cfoutput>
<cfloop array="#request.view#" index="thisView">#view(thisView.section, thisView.item, true)#</cfloop>
</cfoutput>
</cfif>
<cfif isDefined('application.teardown') and isDefined('application.teardown.#request.section#')>
<cfinvoke component="application.teardown" method="#request.section#" fw=this context=request.context service=request.service>
</cfif>
<cfif isDefined('application.cache.#request.section#.after')>
<cfset afterModule = application.cache[request.section].after>
<cfinclude template="#afterModule#">
</cfif>
</cfif>
</cffunction>
<cffunction name="onRequestEnd" returnType="void">
<cfargument type="String" name="targetPage" required=true/>
<cfif not ignoredPath(request.section)>
<cfif isDefined('teardownRequest') and isCustomFunction(teardownRequest)>
<cfset teardownRequest(fw=this, context=request.context, service=request.service)>
</cfif>
</cfif>
</cffunction>
<cffunction name="onSessionStart" returnType="void">
<cfif isDefined('setupSession') and isCustomFunction(setupSession)>
<cfset setupSession(fw=this)>
</cfif>
</cffunction>
<cffunction name="onSessionEnd" returnType="void">
<cfargument name="SessionScope" required=True>
<cfargument name="ApplicationScope" required=False>
<cfif isDefined('teardownSession') and isCustomFunction(teardownSession)>
<cfset teardownSession(fw=this)>
</cfif>
</cffunction>
<cffunction name="sectionExists" returntype="boolean">
<cfargument name="section" required="true" type="string">
<cfif directoryExists(application.path & arguments.section)>
<cfreturn true>
<cfelse>
<cfreturn false>
</cfif>
</cffunction>
<cffunction name="setupApplicationCache">
<cfif fileExists(application.path & 'before.cfc')>
<cfobject type="component" name="application.before" component="before">
</cfif>
<cfif fileExists(application.path & 'after.cfc')>
<cfobject type="component" name="application.after" component="after">
</cfif>
</cffunction>
<cffunction name="setupSectionCache">
<cfargument name="sectionName" required="true" type="string">
<cfset var sectionPath = application.path & arguments.sectionName & '/'>
<cfset sectionPath = replace(sectionPath, '\', '/', "all")>
<cfset var servicePath = sectionPath & 'service.cfc'>
<cfset var setupPath = sectionPath & 'setup.cfc'>
<cfset var beforePath = sectionPath & 'before.cfm'>
<cfset var layoutPath = sectionPath & 'layout.cfm'>
<cfset var viewPath = sectionPath & 'view.cfc'>
<cfset var afterPath = sectionPath & 'after.cfm'>
<cfset var teardownPath = sectionPath & 'teardown.cfc'>
<cfset var beforeExists = fileExists(beforePath)>
<cfset var serviceExists = fileExists(servicePath)>
<cfset var setupExists = fileExists(setupPath)>
<cfset var layoutExists = fileExists(layoutPath)>
<cfset var viewExists = fileExists(viewPath)>
<cfset var teardownExists = fileExists(teardownPath)>
<cfset var afterExists = fileExists(afterPath)>
<cfif serviceExists or setupExists or viewExists or teardownExists>
<cfset application.cache[arguments.sectionName] = structNew()>
<cfset application.cache[arguments.sectionName].path = sectionPath>
<cfif serviceExists>
<cftry>
<cfobject type="component" name="application.cache.#arguments.sectionName#.service" component="#dotPath(servicePath)#">
<cfcatch type="any">
<cfthrow detail="Error instantiating service component #dotPath(servicePath)#">
</cfcatch>
</cftry>
</cfif>
<cfif beforeExists>
<cfset application.cache[arguments.sectionName].before = beforePath>
</cfif>
<cfif setupExists>
<cftry>
<cfobject type="component" name="application.cache.#arguments.sectionName#.setup" component="#dotPath(setupPath)#">
<cfcatch type="any">
<cfthrow detail="Error instantiating setup component #dotPath(setupPath)#">
</cfcatch>
</cftry>
</cfif>
<cfif layoutExists>
<cfset application.cache[arguments.sectionName].layout = layoutPath>
</cfif>
<cfif viewExists>
<cftry>
<cfobject type="component" name="application.cache.#arguments.sectionName#.view" component="#dotPath(viewPath)#">
<cfcatch type="any">
<cfthrow detail="Error instantiating view component #dotPath(viewPath)#">
</cfcatch>
</cftry>
</cfif>
<cfif teardownExists>
<cftry>
<cfobject type="component" name="application.cache.#arguments.sectionName#.teardown" component="#dotPath(teardownPath)#">
<cfcatch type="any">
<cfthrow detail="Error instantiating teardown component #dotPath(teardownPath)#">
</cfcatch>
</cftry>
</cfif>
<cfif afterExists>
<cfset application.cache[arguments.sectionName].after = afterPath>
</cfif>
<cfelseif not (serviceExists or setupExists or viewExists or teardownExists)>
<cfthrow detail="section #arguments.sectionName# is empty or non-existent" message="no section #arguments.sectionName#">
</cfif>
</cffunction>
<cffunction name="setView" returntype="void">
<cfargument name="section" required="true" type="string">
<cfargument name="item" required="true" type="string">
<cfset var thisView = structNew()>
<cfset thisView.section = arguments.section>
<cfset thisView.item = arguments.item>
<cfset request.view[1] = thisView>
</cffunction>
<cffunction name="view" output="true">
<cfargument name="section" required="true" type="string">
<cfargument name="item" required="true" type="string">
<cfargument name="doLayout" default="false" type="boolean">
<cfset var layoutExists = isDefined('action.layout')>
<cfset var requiredServices = ''>
<cfset var serviceMethod = ''>
<cfset var viewExists = isDefined('action.view.#arguments.item#')>
<cfset var viewMetadata = ''>
<cfset checkCache(request.section)>
<cfset var action = cache(arguments.section)>
<cfif viewExists>
<cfset var thisView = action.view[arguments.item]>
<cfset viewMetadata = getMetadata(thisView)>
<cfif isDefined('viewMetadata.service')>
<cfset requiredServices = viewMetadata.service>
<cfelseif isDefined('viewMetadata.services')>
<cfset requiredServices = viewMetadata.services>
</cfif>
</cfif>
<cfif len(requiredServices)>
<cfloop list="#requiredServices#" index="serviceMethod">
<cftry>
<cfinvoke component="#action.service#" method="#serviceMethod#" returnvariable="request.context.#serviceMethod#" argumentcollection="#request.context#">
<cfcatch type="any">
<cfthrow message="unable to invoke #serviceMethod#" detail="section: #arguments.section#; item: #arguments.item#; method: #serviceMethod#">
</cfcatch>
</cftry>
</cfloop>
</cfif>
<cfif isDefined('action.setup.#arguments.item#')>
<cfset var setupFn = action.setup[arguments.item]>
<cfset setupFn(context=request.context, service=request.service)>
</cfif>
<cfif viewExists and layoutExists and arguments.doLayout>
<cfmodule template="#action.layout#">
#thisView(context=request.context, service=request.service)#
</cfmodule>
<cfelseif viewExists>
#thisView(context=request.context, service=request.service)#
</cfif>
</cffunction>
</cfcomponent>
<!---
Application Structure:
Application.cfc
bracketry.cfc
bracketry.js
index.cfm (must be blank)
request.cfm
layout.cfm
dev_section
layout.cfm
service.cfc
before.cfm
setup.cfc
view.cfc
teardown.cfc
after.cfm
setupApplication()
setupSession()
<global_request>
<global_layout>
<section_action>
<section_layout>
<item_action>
<item_view fw=this context=request.context service=request.service />
</item_action>
</section_layout>
</section_action>
</global_layout>
<global_request>
teardownSession()
teardownApplication()
Each plugin should be self-contained
--->