GreyBeard Inc.

    
     

Hastymail 2 ideas

avatar
Basics of the application framework

So I have been taking some time to review the framework and think about how best to alter it to make it work well for a webmail IMAP client instead of a mysql based website. There are not too many changes to the core of how it works but there will be a few. I thought it might be wise to start discussing how this beast works before any code is put into place.

The classes that comprise framework all reside in a single file. Without the mysql bits and other junk we don't need it will be approximately 1200 lines. Some classes are built on others, some are "wrappers" the pull various bits into one place. There are multiple reasons for it's seemingly awkward design and "super clean abstracted OO" is not on that list. I would imagine an OO purist might scoff at my techniques, but I digress.

All page requests go to index.php. It includes only the minimum PHP files at first, and here we check our configuration and include any other php files on as needed bases. It kicks off the two important objects, $user, and $pd. $user comprises the "backend" and $pd handles outputting the page.

Part of the design of this code is to centralize functions/methods that do similar tasks, and to ease the job for the programmer to handle those tasks (and of course to separate presentation). When the $user object is started we check the status of our login, handle a login action, a logout action, setup/tear down a session,  then process _POST data, then process _GET data.  Logins are "special" in that they are handled by the core code, all other _POST data is handled by the form processing system after we determine if we are logged in or not.

forms in this system must be registered in a separate file. This requires creating an array that has all the form field names and types, whether they are required or not, as well as a label for automatic notices.  Each from definition in this file is keyed by the name of it's submit button (not it's value).  So an example entry for a form might be like this:

'flag_message' => array(
    'message_id' => array('int', 1, 'Message ID'),
    'mailbox' => array('string', 1, 'Mailbox'),
),

which would correspond to a form written like this:

<form method="post" action="index.php">
<input type="hidden"  name="message_id" value="1" />
<input type="hidden" name="mailbox" value="INBOX" />
<input type="submit" name="flag_message" value="Flag" />
</form>

So what framework does is check for a non-empty _POST. If so then it includes the post processing PHP files then starts the system. The system looks at all the defined buttons in the registered list and checks to see if one exists in _POST. If so it goes through the defined fields and checks for the presence and correct type of any required for this form. If the form fails notices for the user are gathered and the POST data is made available to the presentation code in such a way as to make it trivial to repopulate the form while telling the user what they did incorrectly. If the form passes the requirements a method is called in a post function file, named form_action_<button_name>. This method gets the form definition and the raw post data handed to it. These methods are where we then process any remaining error checking, do something with the submitted data, then set either error flags or completion notices for the presentation code.

The _GET processing system is currently based on clean urls (like at the this site), but it won't take much to modify, and there are some non-clean url bits in place already. I plan on creating a similar system for _GET processing, including a type list as well as a "trigger system" that fires off a method. So for example we could require every  url to have a page arg and it's value, assuming its defined in the list, would trigger a url_action_<page value> method to run. The _GET processing runs after the _POST, and here we setup any data we need to pass onto the presentation side.

Presentation is handled by yet another trigger system, this one hinging on a value I mysteriously call "dsp_page". This is set to "not_found" by default, and when we check the page arg on the url for a valid value, in each of the corresponding url_action functions we set dsp_page to whatever page we want to display (compose, mailbox, message, etc). So we set dsp_page to what we want to see, we grab any data from whatever source we need (imap, mysq, etc), then the url_action function exits, and the template system begins. All pages, except those short circuited somewhere along the line (such as outputting rss), call the main template. It in turn can call methods to drop in "chunks" of the page. In the primary content area of the page, the last trigger is run, and a method called print_<dsp_page value> is run to populate that area.

Whats nice about this system is lets say we want to add a compose page. First thing we do is define "compose" as a valid value for the "page" url arg. Then we take our browser there. It dies with a fatal error because there is no "url_action_compose" method. We create that and prep the page info we will need then set dsp_page to 'compose'. Refresh the page and we have a new error, no "print_compose" method. We add that and thats it, we have a new page in our application.  It is also possible to call another template from the main template if we choose to, which can be handy when we have a significantly different page to render.

url_action functions are grouped together in a file. form_action functions are also grouped together in there own file (and only even included if POST is not empty) and print_ functions are also grouped together in a file. I have used this arrangement for some large projects and with only a few modifications on occasion it has the very nice benefit of each file staying at a maintainable size.

So hopefully some of that makes sense to somebody other than me. Lord knows I should not be writing anything to anybody anywhere at 3 in the morning.

Reply /Quote