3. WHO AM I?
• Luis Majano
• Computer Engineer
• Born in El Salvador ->Texas
• CEO of Ortus Solutions
• Adobe Community Professional
• ColdFusion (CFML) Advocate
• Adobe Advisory Committee
• Lucee Language Committee
• Sandals -> ESRI -> Ortus
@lmajano
@ortussolutions
5. What is MVC?
• One of the most common UI design patterns
• Separates logic into three tiers or layers
• Model
• View
• Controller
• Separation of concerns is KEY
• Time to evolve your spaghetti code
M
C
V
6. What’s the problem?
CFMTemplate
Queries
If statements
URL/Form
Cleanups
CFC calls
HTML/JS/CSS
Embedded CFC
calls
Embedded
Queries
Tags
More Queries
More CFC calls
Includes?Includes
Spaghetti Hell
7. What is the problem?
• CFM page for each URL in the application
• Pages execute from top to bottom
• Typically 100's of lines of code per page
• I have seen 1000’s
• Mix of business logic and display code
• Maybe some code reuse via <cfinclude> or
custom tags or basic CFCs
CFMTemplate
Queries
If statements
URL/Form
Cleanups
CFC calls
HTML/JS/CSS
Embedded CFC
calls
Embedded
Queries
Tags
More Queries
More CFC calls
Includes?Includes
9. Spaghetti Fun Comments
<!—- Do not remove the following lines or things break —>
<!— Dont’ know what this variable does, but don’t touch it —->
<!—- Remove at your own risk —->
<!—- I have no idea where this variable is set —>
10. Downsides
• Hard to maintain, especially as application evolves
• Hard to distribute work to teams
• Code duplication
• Violates the D.R.Y. principle
• Can't build an API from the business logic
• Can't perform automated tests on the business logic
• At the end: it costs time -> money!
11. Benefits of MVC
• Separation of Concerns
• Same model – different views (GUIs)
• Increase Maintainability
• IncreaseTestability
• Increase Decoupling
• Better Abstractions
17. HOW IT WORKS?
• Single page index.cfm (front controller)
• Executions via form/url with param called event
• Request Context (Simulates Client Request)
• form/url » RC
• PRC » Private Struct
• Handlers Controls what happens next?
• Layout/View
• Relocation
• Data
http://localhost/index.cfm?event=users.index
http://localhost/users/index
Traditional
*Routing
ColdBox Event: users.index
18. REQUEST CONTEXT
Request Collection (RC)
REMOTE
URL
FORM
• FORM/URL/Remote = RC
• FORM variables take precedence
• Private Request Collection (PRC) = request scope
• Abstractions
• Best practice to separate what’s client and what’s your app
• Live inside the Request Context Object
• coldbox.system.web.context.RequestContext
• This object lives in the REQUEST scope
• Used for REST, Headers, Sending Files, and much more
20. ANATOMY OF A ROUTED URL
• Package = A Directory in the handlers folder
• Handler = A handler CFC in the handlers folder
• Action =The method to execute in the handler, defaults to index
• This combination is called a ColdBox Event
http: //localhost/{package}/{handler}/{action}?querystring
event=package.handler.action
Event
Route
23. HANDLER CODE
component name=“users”{
property name=“myService” inject=“MyService”;
function index( event, rc, prc ){
return “Hello from ColdBox Land”;
}
function login( event, rc, prc ){
prc.data = myService.getData();
event.setView( view=“handler/login”, layout=“login” );
}
function list( event, rc, prc ){
var data = getModel( “myService” ).list();
return data;
}
function create( event, rc, prc){
var oUser = populateModel( myService.new() );
myService.save( oUser );
relocate( “user.index” );
}
}
models/MyService.cfc
variables.myService
Every action has 3 arguments:
Request Context + Struct
References
Handlers can return HTML
natively
Set a view + layout for
rendering
Get Models instead of injection
Complex data returns as JSON
by default
Objects can be populated from
FORM/URL automatically
24. MODEL CODE
component
extends="cborm.models.VirtualEntityService" singleton{
function init(){
super.init( entityName="User" );
return this;
}
function list(){
return queryExecute( "select * from users order by lname" );
}
array function getTopVisitedContent( numeric max=5 ){
return newCriteria()
.list(
max = arguments.max,
sortOrder = "hits desc",
asQuery = false
);
}
}
WireBox Persistence