The SitePoint Forums have moved.

You can now find them here.
This forum is now closed to new posts, but you can browse existing content.
You can find out more information about the move and how to open a new account (if necessary) here.
If you get stuck you can get support by emailing forums@sitepoint.com

If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

(You could also leave out the include_once('frontcontroller.inc.php') part if you are using Apache and instead use the auto_prepend_file directive in a .htaccess file.)

Yes, I am combining the Controller and the View (which is perfectly acceptable). This is on purpose. You could put the $user =& new User($_GET['id']); line (and anything else) in its own UserController class if you'd like to acheive better separation, but simplicity is one of my design goals here.

Could it be possible, on the page that is including FrontController.class.php to have a class declaration, without being declared twice? I like this idea a lot, but my pages all use a class, with an interface that the front controller knows, and the fron controller executes the page controller class.

This lets you also extend a BaseCommand class if you wanted. This is exactly what I've been looking for in a FrontController/PageController! You don't have to use a prepend to execute your command class!

I think that the [PRE]$t = microtime()[/PRE] in the frontcontroller.inc.php file breaks the encapsulation of the timing filter. Shouldn't this go into the construction of the timing filter? (preprocessing in the constructor, post processing in the run) I realize that this would slightly reduce the reported time, but then I always thought it was unseemly for scripts to report their own execution time, anyway.

Selkirk, I have a great deal of respect for your opinions, so I'm very pleased by your comments -- I was secretly hoping you'd contribute to this thread.
As an aside, I've got to say that I consult your WACT documentation frequently to aid in the development of my own framework.

Originally Posted by Selkirk

I think that the $t = microtime() in the frontcontroller.inc.php file breaks the encapsulation of the timing filter.

You're right, but I did it purposefully so I could have an more accurate estimation of execution time. However, passing an argument to the TimeFilter constructor is optional, and if no argument is passed, the initial time ($t0) is calculated during preprocessing (see the first line of the run() method).

Originally Posted by Selkirk

Shouldn't this go into the construction of the timing filter? (preprocessing in the constructor, post processing in the run)

I agree that it makes more sense to set the initial time in the TimingFilter constructor. However, I disagree that preprocessing should (in general) occur in the constructor. This would result in preprocessing happening for all the filters in the FilterChain, whether they are executed or not. If, for example, there were an AuthenticationFilter (high in the FilterChain) that determined the user should be redirected to a login page, it would be a waste for the PageCachingFilter (lower in the FilterChain) to perform pre-processing since it would never be executed. In other words, each filter should have the ability to cease execution of the FilterChain and commence post-processing (by not calling $fc->next()), therefore preprocessing should only occur if it needs to.

Originally Posted by Selkirk

I realize that this would slightly reduce the reported time, but then I always thought it was unseemly for scripts to report their own execution time, anyway.

Yeah, I agree -- it's really just intended for testing, and I thought it would be good as an example. I also have an XdebugFilter for more informative profiling (thanks to your recommendation in the WACT documentation).

Originally Posted by Selkirk

I don't think the "include back"/exit technique is a good idea.

Could you expand on this? I know it's not the most efficient way of doing things, but it was the best method I could come up with to get post processing to happen after normal page execution.

PHP4 support is one of my design requirements, so I'm not considering any PHP5-specific functionality, although I suppose using destructors may be an alternative if I could use them.

The problem with register_shutdown_function is this:

Originally Posted by PHP Manual

Multiple calls to register_shutdown_function() can be made, and each will be called in the same order as they were registered.

But I need them to be called in the opposite order as they were registered because the first filter to do pre-processing should be the last to do post processing, the second should be next to last, etc. Like so: Decorator sequence diagram [microsoft.com]

Also:

Originally Posted by PHP Manual

The registered shutdown functions are called after the request has been completed (including sending any output buffers), so it is not possible to send output to the browser using echo() or print(), or retrieve the contents of any output buffers using ob_get_contents().

(Emphasis added.)
I don't like that last part either since it detracts from the power of the Intercepting Filter pattern.

Selkirk, I have a great deal of respect for your opinions, so I'm very pleased by your comments -- I was secretly hoping you'd contribute to this thread.
As an aside, I've got to say that I consult your WACT documentation frequently to aid in the development of my own framework.

Thanks. I've been meaning to get into this thread sooner or later. I'm glad someone uses the documentation. I've been working on the Front Controller / Page Controller / Intercepting Filter / Application Controller aspects of WACT. I've been slowly writing things out. I just did the first draft of Intercepting Filter.

However, I disagree that preprocessing should (in general) occur in the constructor.

Oops. You are right. I didn't look carefully enough at what was going on. One thing, though. I would hate to see filter classes being included and instantiated, but never called. Seems like a waste.

I also have an XdebugFilter for more informative profiling (thanks to your recommendation in the WACT documentation).

Thats probably Harry's recommendation. I haven't used it yet, but I am interested in it.

Could you expand on this? I know it's not the most efficient way of doing things, but it was the best method I could come up with to get post processing to happen after normal page execution.

I guess I can't really say much about this other than double declarations (includes) are bad, m'kay.

I wrote about some alternate methods on the wiki.

Here is what I've done so far on the intercepting filters in WACT. These are untested proofs of concept. I've tried to start minimally with just straight includes.

3. Should be possible to execute a page controller without the frontcontroller. In other words if you remove the;

PHP Code:

include_once 'frontcontroller.inc.php';

from the page controller, the page contoller still "works". This rule should help make the front controller / intercepting filters re-usable. Also (in theory) if should be possible to take an existing project like phpBB, strip out all it already has for front contoller / incepting filter type logic while preserving the existing page controllers.

4. Does does not depend on any Apache specific features or php.ini settings. Although auto_prepend is nice not all hosts give users the ability to change such settings (plus not everyone is using Apache so need to be careful of which $_SERVER variables are used).

There's probably some more but just kicking off - anyone with more please add them.

On the exit() issue, that also makes me nervous somehow but right now don't have a specific reason. My guess is it may limit flexibility in some situations but don't have a specific example.

An alternative approach may be to wrap the example_page.php in a function which is called from PageController but if this needs to be hard coded into example_page.php, it's already violating point #3 above. Not sure...

1. Developer writes example_page.php
2. Some process is performed which automatically update example_page.php and wraps it's contents in a function plus includes frontcontroller.php at the start.
3. End users (site visitors) execute the modified version

The advantage there could also be to add another function to the page controller which contains data needed by intercepting filters to complete their tasks e.g;

If example_page.php is placed somewhere outside of the web root, for example, then "deployed" into the web root with some script which can either be manually executed by a developer or the Apache 404 trick (see here) e.g.;

Code:

ErrorDocument 404 /deployer.php

Not 100% sure again. This should allow re-usability without too much difficulty but whether I'd actually enjoy developing PHP scripts in this type of "environment" I don't know.

1. Developer writes example_page.php
2. Some process is performed which automatically update example_page.php and wraps it's contents in a function plus includes frontcontroller.php at the start.
3. End users (site visitors) execute the modified version

The advantage there could also be to add another function to the page controller which contains data needed by intercepting filters to complete their tasks e.g;

Much of the J2EE architecture is designed with a "Deployment phase" in mind. I think one of the advantages that PHP has over java is easy deployment. Deployment in PHP is mostly a copy to the web server. Interestingly, one of the touted benefits of struts is that it frees the java developer from the web server's deployment phase. The current WACT template implementation does not require a deployment phase because the templates are compiled automatically on demand. Could a code generation technique applied to front controllers & intercepting filters also avoid requiring a Deployment Phase? Without contradicting the "naive application logic" model that codezilla seems to be pursuing?

BTW, I'd also like to make a distinction between a front controller, which I believe has to provide some sort of command dispatching for core logic with what I am calling a filter manager, which simply calls and sequences filters around that logic. I would call frontcontroller.inc.php in codezilla's example a filter manager, not a front controller. A front controller and filter manager could easily be implemented in the same class, however.

If you require the use of auto_prepend_file, why not just also also require the use of auto_append_file and eliminate the tricky code altogether?

I don't require its use. In fact, it is one of my design requirements that I don't use auto_prepend_file, or any other Apache-specific functionality -- which is why I used include(). I only asked the question to see if you felt that it would be a bad practice. Perhaps I should rephrase the question:

In your opinion, would it still be bad to have exit; in frontcontroller.inc.php if it were called using the auto_prepend_file mechanism instead of include()'ing it at the top of every page, disregarding the option of using auto_append_file?

I've been trying to decide whether or not to make the jump from a simple "procedural" include style designed to work with auto_prepend_file to a class oriented style.

Opinions?

I (obviously) recommend that you implement a class oriented style for WACT, especially since it is very object-oriented in nature. Of course, keeping things as simple as possible.

Personally, my main reason for taking the class oriented InterceptingFilter route was to have the ability to easily turn on/off certain pre/post-processing logic. Also, I wanted to do post-processing without using an append file because post-processing logic is usually tied (conceptually) to pre-processing logic. In fact, you mention this on the InterceptingFilter Wiki page:

Originally Posted by WACT Wiki

In one approach, the filters can be strung together in a chain and the chain of filters can be passed to the first filter. Then each filter may call the next filter on the chain when it is ready. This allows the filter to do both pre-processing and post-processing. it also allows the filter to couple the pre and post processing.

I never thought much about it in these terms before, but that's exactly why I've never liked using append files -- they separate the pre/post-processing code.

Ultimately, I came up with all the above code (from Post #1) just to have a simple page caching mechanism that could be applied to all pages, with the ability to easily add/remove different filters in the future.

BTW, I'd also like to make a distinction between a front controller, which I believe has to provide some sort of command dispatching for core logic with what I am calling a filter manager, which simply calls and sequences filters around that logic. I would call frontcontroller.inc.php in codezilla's example a filter manager, not a front controller. A front controller and filter manager could easily be implemented in the same class, however.

Good point. As I see it (and should have said it) my frontcontroller.inc.php also contains all the code common to the application: require()s, include()s, define()s, ini_set()s, and whatever else is needed. I personally don't like the index.php/module/page mechanism; however, I was trying to accomplish a similar objective in a different way. Anything that normally goes in your index.php (which is a front controller) could instead go in the include()'d frontcontroller.inc.php.

The reason I still consider my example to be a front controller is because it does do dispatching, or at least what I consider (possibly incorrectly) to be dispatching. It dispatches to the requested page: include($_SERVER['PATH_TRANSLATED']). Granted, it's a very simple front controller, but a front controller nevertheless.

Perhaps I should rename PageControllerFilter to RequestDispatchingFilter which (hopefully) does a better job of describing its purpose. RequestDispatchingFilter could then contain "command dispatching for core logic" and use include($_SERVER['PATH_TRANSLATED']) as a special (or even default) case.