Putting all my controller thoughts together...
Moderator: General Moderators
Putting all my controller thoughts together...
This is currently heavily mocked, but this is what I see to be evolving towards:
Execution begins at a Front Controller (but I need to escape out for a lot of legacy code)
The Front Controller preforms some setup (creates the Registry, creates the central DB object, sticks it in the registry, etc)
The FC then uses a Dispatcher/Mapper to select which "Module Controller" to pass control to and executes the Module Controller.
If no Module controller is configured it falls back to simply invoking the requested script(suitably cleansed), if it exists or a 404 if it doesn't. (Thereby reaching all the old legacy pages.) The FC can normally idenify the MC to select based on the first component of the URL passed the root of the application install.
The Module Controller
Parses the remainder of the URL to identify a Command chain and a Request type and per-event DB, if needed.
Instantiates the identified Request object and passes it to a the Command Chain.
Command chain returns the Response to send to the browser.
Echos the Response.
Its a "slightly distributed" Front Controller -- due to the re-parse on every page invocation nature of PHP I don't want to use a single master configutation file to establish the mappings nor do I want to hard code it into a single class. Thus the MC's which each handle their collection of actions. The MC's are not meant as "Application Controllers" as they still handle the Input Controller aspect as well. Many of the MC's need to establish a second database connection to a database identified by yet another URL component -- and the identified Request will need access to the DB immediately to finish its validation of the inputs.
Does this sound reasonable?
Execution begins at a Front Controller (but I need to escape out for a lot of legacy code)
The Front Controller preforms some setup (creates the Registry, creates the central DB object, sticks it in the registry, etc)
The FC then uses a Dispatcher/Mapper to select which "Module Controller" to pass control to and executes the Module Controller.
If no Module controller is configured it falls back to simply invoking the requested script(suitably cleansed), if it exists or a 404 if it doesn't. (Thereby reaching all the old legacy pages.) The FC can normally idenify the MC to select based on the first component of the URL passed the root of the application install.
The Module Controller
Parses the remainder of the URL to identify a Command chain and a Request type and per-event DB, if needed.
Instantiates the identified Request object and passes it to a the Command Chain.
Command chain returns the Response to send to the browser.
Echos the Response.
Its a "slightly distributed" Front Controller -- due to the re-parse on every page invocation nature of PHP I don't want to use a single master configutation file to establish the mappings nor do I want to hard code it into a single class. Thus the MC's which each handle their collection of actions. The MC's are not meant as "Application Controllers" as they still handle the Input Controller aspect as well. Many of the MC's need to establish a second database connection to a database identified by yet another URL component -- and the identified Request will need access to the DB immediately to finish its validation of the inputs.
Does this sound reasonable?
I'm running into a few conceptual issues as I work throught this. I'm probably second guessing TDD too much and trying to guide it somewhat to avoid some obvious bad designs.
The difficulty surrounds my Context and Request class hierachies/familes.
There's close to a 1:1 mapping of Requests to form Handlers. However there is some commonality amoung the force-type custom url parameters. A typical Context is shared between several Handlers ( probably closest to a UnitOfWork).
For instance: one "module" of the application is "SlidingDoorsAdmin" with its own Controller reached from the front controller. Url's claimed by this Controller are of the form /register/[-A-Za-z_0-9]+/admin/[-A-Za-z_0-9]*
I think that upon reaching the SDA Controller, I want to create a SdaRequest that exposes a getUnixName() and a getScriptName().
The SDA Controller will need to first test if the found UnixName is a valid competition and one that is in a state that allows admin features to be used. If its a valid competition it will look up what handler chain to invoke give the ScriptName. If it finds a handler chain, it will have to "upgrade" the SdaRequest to the appropriate ScriptRequest.
Now the parts that feal awkward to me here:
The universal requirement to screen for a valid UnixName: this feels very similar to an early component in a handler chain. I think this is telling me that instead of having the front controller dispatch to a module controller, I should view the module controller as simply a handler ( but that that will also dispatch). Thus the Front Controller matches the URLs for this handler chain, and kicks off with the InvalidSDAHandler, which chains to a ValidSDAHandler or similiar that creates the Request/Context and kicks off the next dispatcher. Does this sound reasonable?
Now the issue of "upgrading" from a base class to a more specified class... Any suggestions?
Here this image might help explain

Its not 100% accurate -- I don't have a seperate Action class, its simply the "invoke" method of a handler. The Controller identifies the handler that wants to claim the request, then initialized the Context/Request asked for by that Handler and invokes the handler, passing in the Context and Request.
EDIT:
I've made my first attempt at tackling the "upgrade" issue. I now have the first of the "ModuleRequests" and then refactored the existing ScriptRequest. In the current system, the script request takes a module request in its constructor and stores in in a class variable. Then ~3-4 facade type methods are provided for access to the underlying variables. Ie composition not inheritence.
I suspect there will be some shared across all request features, so I think that the Module Requests will end up extending off a common base class. I suspect that the Script requests will likewise subclass of a separate common base class ... ie something like
The AbstractSdaScriptRequest handles the facade between the composed SdaRequest.
As a result there are two Request "types" in the application -- one created at the module selection level and used in the script selection logic. And one created in the script selection level and used in the actual handler logic. I suspect something similar might happen with the contexts. So I'll end up with two pairs of paired hierarchies -- starting to become a smell, but I think I'll have to wait and see how it developers, unless y'all have any thoughts?
The difficulty surrounds my Context and Request class hierachies/familes.
There's close to a 1:1 mapping of Requests to form Handlers. However there is some commonality amoung the force-type custom url parameters. A typical Context is shared between several Handlers ( probably closest to a UnitOfWork).
For instance: one "module" of the application is "SlidingDoorsAdmin" with its own Controller reached from the front controller. Url's claimed by this Controller are of the form /register/[-A-Za-z_0-9]+/admin/[-A-Za-z_0-9]*
I think that upon reaching the SDA Controller, I want to create a SdaRequest that exposes a getUnixName() and a getScriptName().
The SDA Controller will need to first test if the found UnixName is a valid competition and one that is in a state that allows admin features to be used. If its a valid competition it will look up what handler chain to invoke give the ScriptName. If it finds a handler chain, it will have to "upgrade" the SdaRequest to the appropriate ScriptRequest.
Now the parts that feal awkward to me here:
The universal requirement to screen for a valid UnixName: this feels very similar to an early component in a handler chain. I think this is telling me that instead of having the front controller dispatch to a module controller, I should view the module controller as simply a handler ( but that that will also dispatch). Thus the Front Controller matches the URLs for this handler chain, and kicks off with the InvalidSDAHandler, which chains to a ValidSDAHandler or similiar that creates the Request/Context and kicks off the next dispatcher. Does this sound reasonable?
Now the issue of "upgrading" from a base class to a more specified class... Any suggestions?
Here this image might help explain

Its not 100% accurate -- I don't have a seperate Action class, its simply the "invoke" method of a handler. The Controller identifies the handler that wants to claim the request, then initialized the Context/Request asked for by that Handler and invokes the handler, passing in the Context and Request.
EDIT:
I've made my first attempt at tackling the "upgrade" issue. I now have the first of the "ModuleRequests" and then refactored the existing ScriptRequest. In the current system, the script request takes a module request in its constructor and stores in in a class variable. Then ~3-4 facade type methods are provided for access to the underlying variables. Ie composition not inheritence.
I suspect there will be some shared across all request features, so I think that the Module Requests will end up extending off a common base class. I suspect that the Script requests will likewise subclass of a separate common base class ... ie something like
Code: Select all
AbstractModuleRequest <--- SlidingDoorsAdminRequest
<--- ResultTrackerRequest
AbstractScriptRequest <-- AbstractSdaScriptRequest <--- SpecificSdaScriptRequestAs a result there are two Request "types" in the application -- one created at the module selection level and used in the script selection logic. And one created in the script selection level and used in the actual handler logic. I suspect something similar might happen with the contexts. So I'll end up with two pairs of paired hierarchies -- starting to become a smell, but I think I'll have to wait and see how it developers, unless y'all have any thoughts?
I know that feeling
been working as a pure hourly contractor for about 6 months, with no scheduled vacation days... Just switched to a "new" job doing almost the same thing, but am now salaried so I have vacation days again.... can't wait to start using them...
Jason is suggesting Adaptors over at SP for this, but that doesn't feel quite right either.....
Jason is suggesting Adaptors over at SP for this, but that doesn't feel quite right either.....
Yes. This handler would "claim" the request if the name is not valid. I'm not sure about dispatching though. Could this simply be dealt with by configuring different chains based on the request type identified by the FrontController?The universal requirement to screen for a valid UnixName: this feels very similar to an early component in a handler chain. I think this is telling me that instead of having the front controller dispatch to a module controller, I should view the module controller as simply a handler ( but that that will also dispatch).
I haven't understood the dual request objects. Would a single request object which contains everything for all the handlers make sense?
Well its a "large" application, its currently seperated into slightly arbitrary modules.
I have modules for
Competition Registration (registering, updating registration, cancelling, statistics on registration generation, on-line payment -- all with plenty of business logic),
Competition Administration (admin overrides, payment tracking/reporting, MOTDs, email announcements, list export for printed programs or other third-party applications)
Result Tracker (importing results(a rather large wizzard), point tracking/calculation, browsing(heavily force-type/mod_rewrite for clean urls))
Beta versions of about three other large features, plus the "normal" account management, simple announcement/calander system, etc.
There's probably over ~100 "actions" at present and I'm hoping as I get into this refactoring that i can accelerate the development. There's no way a single "rich" Request object could be constructed in a useable fashion. Each module has between 10 and 40 actions I think.
So the FrontDispatcher parses the URL and finds the appropriate module. This module looks like a regular handler chain to the Front Dispatcher, but will do its own dispatching to find either an action/handler chain or an application controller. The first "module" handler chain is where the lack of a valid "UnixName" can be caught and handled, before a lot of expensive setup is done for the module's context. The secondary within the module handler chain, is the more traditional handler chain we've been talking about, with the check for InvalidRequest, AccessDenied, etc as those need to be configured on a per-action basis.
I have modules for
Competition Registration (registering, updating registration, cancelling, statistics on registration generation, on-line payment -- all with plenty of business logic),
Competition Administration (admin overrides, payment tracking/reporting, MOTDs, email announcements, list export for printed programs or other third-party applications)
Result Tracker (importing results(a rather large wizzard), point tracking/calculation, browsing(heavily force-type/mod_rewrite for clean urls))
Beta versions of about three other large features, plus the "normal" account management, simple announcement/calander system, etc.
There's probably over ~100 "actions" at present and I'm hoping as I get into this refactoring that i can accelerate the development. There's no way a single "rich" Request object could be constructed in a useable fashion. Each module has between 10 and 40 actions I think.
So the FrontDispatcher parses the URL and finds the appropriate module. This module looks like a regular handler chain to the Front Dispatcher, but will do its own dispatching to find either an action/handler chain or an application controller. The first "module" handler chain is where the lack of a valid "UnixName" can be caught and handled, before a lot of expensive setup is done for the module's context. The secondary within the module handler chain, is the more traditional handler chain we've been talking about, with the check for InvalidRequest, AccessDenied, etc as those need to be configured on a per-action basis.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
I can't help but get the sense that you have overcomplicated things, but it may just be complicated. A couple of thoughts: first is that you may want to have multiple Front Controllers and collapse your Front/Module Controllers into those. There is no rule that says you can only have one Front Controllers and is sounds like your Module Controllers are really Front Controllers.
The other thought is that you may want to put more information into your action parameters. I often have actions like:
index.php?action=mymodule/myaction
That way I can organize the actions in a heirarchy. You seem to need a little of both.
The other thought is that you may want to put more information into your action parameters. I often have actions like:
index.php?action=mymodule/myaction
That way I can organize the actions in a heirarchy. You seem to need a little of both.
I'm looking at this from the point of view that there is only one http request and that's what gets passed around. Is the richness coming from other (domain) items being added to the request over and above the user input?nielsene wrote:There's no way a single "rich" Request object could be constructed in a useable fashion. Each module has between 10 and 40 actions I think.
The multiple FC's is an option, I guess, as it is basically what I'm doing. Especially if I create an abstract FC from which to inherit the common functionality.
Currently the module and action are apparent from the URI. I have an extreme dislike of GET URL's, so I make ample use of mod_rewrite or ForceType.
Ie I much prefer
mymodule/myaction
to
index.php?action=mymodule/myaction
Most of my mdoules have one requirement parameter, and that will get inserted into the url like
mymodule/mdoule_param/myaction
With very few exceptions any parameters for myaction are either in POST or also embedded into the URL (if it should be bookmarkable).
Currently the module and action are apparent from the URI. I have an extreme dislike of GET URL's, so I make ample use of mod_rewrite or ForceType.
Ie I much prefer
mymodule/myaction
to
index.php?action=mymodule/myaction
Most of my mdoules have one requirement parameter, and that will get inserted into the url like
mymodule/mdoule_param/myaction
With very few exceptions any parameters for myaction are either in POST or also embedded into the URL (if it should be bookmarkable).
Perhaps I took the wrong messsage away from one of you earlier posts. You should a Request object with named accessors for the paramters needed by a given Command/Action/Handler. I think you even had the Request having an "isValid" that the InvalidRequestHandler could simply query -- such a method has to be tailored for the given action.McGruff wrote:I'm looking at this from the point of view that there is only one http request and that's what gets passed around. Is the richness coming from other (domain) items being added to the request over and above the user input?nielsene wrote:There's no way a single "rich" Request object could be constructed in a useable fashion. Each module has between 10 and 40 actions I think.
Nothing extra is abeing added to the Request -- its merely a gateway to the Post/Custom Url Parameters, with named accessors. Its read-only.
The Context has the other aspects and is writeable by the Handlers. Database connection, Data Mappers, Session. It'll probably also have the "View Helper" type things, when I get that far. But again a Context tends to be customied with named accessors at something between the Module Level and the Action level -- An application controller would definitly end up with its own subclass of the module's context. More complicated scripts as well.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Your architecture looks normal except for the Contexts. It is really not clear to me why you are doing what you are doing, but I get the sense that it is your strange Context implementation that is causing your problems. Perhaps a Locator or Dependency Injection might be a solution if your problem is very complex. But probably simplifying things and getting rid of some unnecessary requirements that you are imposing on your design might help you refactor.
Well its the Requests that are causing the problems. The Contexts just make a second case of the same problem, but its smaller for them as they don't get subclassed as often.
The Context is basically a locator. It provides access to a PhraseBook and to DB connections. Its also my Session/Unit of Work gateway (as the Requests I use are read-only.)
The Context is basically a locator. It provides access to a PhraseBook and to DB connections. Its also my Session/Unit of Work gateway (as the Requests I use are read-only.)
Or perhaps I'm giving out the wrong message to begin with.. This is just my own approach. It could be, for example, that the request syntax check should get at least part of the specification (valdidation rules) from the domain.nielsene wrote:Perhaps I took the wrong messsage away from one of you earlier posts. You should a Request object with named accessors for the paramters needed by a given Command/Action/Handler. I think you even had the Request having an "isValid" that the InvalidRequestHandler could simply query -- such a method has to be tailored for the given action.
I think we were talking about "context" a while back in relation to the presentation context - http/cli. Is you're context code more of a domain model? This could work well as a service locator with domain objects lazy-loaded in a Registry by the controller, then read later by the view (as I think Arborint was saying). The view and controller are kept nicely separated.
Testing the controller ought to be fairly straightforward since you can mock domain objects managed by the locator - or even the locator itself. I think once you've decided what the request type is and what script should handle it you've basically moved out of the controller and into the domain.
I think we're talking past each other here.
I suspect in your architecture my Context would simply be part of your Request, maybe partially split to a Registry. The initial decision on my part was that I needed some place to put the Session/Unit of Work type objects. In my mind set they don't belong in the Request, since the Request should be read-only. The context is also a useful place to put a references to a registry and try to avoid a globally accessible singleton style approach for the regstry.
I could simply add the Request as one of the items managed by the Context's registry. Then I'd "only" have a Context... my Context would basically be synamous with your Request then. However as basically everything would start off with a $request=$context->getRequest(); style call, I'm passing them both explictily.
Plus the Context is basically the Model/Domain gateway for the Controller.
I suspect in your architecture my Context would simply be part of your Request, maybe partially split to a Registry. The initial decision on my part was that I needed some place to put the Session/Unit of Work type objects. In my mind set they don't belong in the Request, since the Request should be read-only. The context is also a useful place to put a references to a registry and try to avoid a globally accessible singleton style approach for the regstry.
I could simply add the Request as one of the items managed by the Context's registry. Then I'd "only" have a Context... my Context would basically be synamous with your Request then. However as basically everything would start off with a $request=$context->getRequest(); style call, I'm passing them both explictily.
Plus the Context is basically the Model/Domain gateway for the Controller.