Neptune takes heavy advantage of Page Controllers.
Most ColdFusion frameworks - at least the so-called MVC frameworks - are really Front Controllers. That is, they handle incoming requests and coordinate processing among multiple requests. Per Martin Fowler, a Front Controller is "A controller that handles all requests for a Web site."
A Page Controller is "An object that handles a request for a specific page or action on a Web site." (again, per Fowler).
In Neptune, a page controller is a .cfc file in the same folder as the .cfm for which it is the page controller and with the same file name (excepting the extension). So, a file called "sample-page.cfm" would have a "sample-page.cfc" for a page controller (if one is needed).
The code to call a page controller from a page would be the following:
The page controller itself must have a "loadData" method that will return a structure of data that will be appended to the variables scope of the page.
Here is a simple page controller:
<cfcomponent extends="_framework.PageController" output="no"> <cfset loadExternalVars("Sections,Pages")> <cfset setInherits(variables.Sections)> <cffunction name="loadData" access="public" returntype="struct" output="no"> <cfset var local = StructNew()> <cfset var vars = StructNew()> <cfset require("URL.id","numeric","/index.cfm")> <cfset default("URL.section","numeric",0)> <cfset vars.Title = "Sample Page"> <cfset vars.qSection = 0> <cfset vars.qPages = 0> <cfif URL.section> <cfset vars.qSection = variables.Sections.getSection(URL.section)> <cfset vars.qPages = variables.Pages.getPages(URL.section)> <cfset vars.Title = "#vars.Title# in #vars.qSection.SectionTitle#"> </cfif> <cfreturn vars> </cffunction> </cfcomponent>
Let's go through this example.
<cfcomponent extends="_framework.PageController" output="no">
It is essential that the page controller extends "_framework.PageController". This provides a number of available methods:
This line (which should be in the Psuedo-constructor - outside of any method) fires the loadExternalVars method.
So, in our example code, Application.Sections and Application.Pages would be copied to variables.Sections and variables.Pages.
<cffunction name="loadData" access="public" returntype="struct" output="no">
The "loadData" method (which must return a struct) is essential to create data on the page. Creating data in the page controller in this fashion enables the .cfm to only have display code - making it easy to be edited by someone who only knows display.
<cfset var local = StructNew()> <cfset var vars = StructNew()>
By convention, the "local" variable is a structure for any variables that need to be created within the loadData method, but not returned from it. The "vars" variable is for any variables that should be returned by the method and therefor become part of the variables scope of the calling .cfm template.
The require method ensures that a variable exists and is valid. If the variable does not exist with a valid value, then the browser is sent to the URL indicated.
The default method set a variable to the given value if it is not a valid value. So, if the variable either is not set or is set to a value not of the type specified, the default function will set it to the default value.
<cfset vars.Title = "Sample Page"> <cfset vars.qSection = 0> <cfset vars.qPages = 0>
By convention, it is suggested that you first set default values for any variables being returned by the "loadData" method. After that, you can manipulate those variables as needed.