Site framework with optional modules

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
Heavy
Forum Contributor
Posts: 478
Joined: Sun Sep 22, 2002 7:36 am
Location: Viksjöfors, Hälsingland, Sweden
Contact:

Site framework with optional modules

Post by Heavy »

I am about to make a framework for different site capabilities using a template caching template engine I wrote.
I want to create a system that can "load" modules. I plan to be able to reuse the framework for different applications.

So all intended applications have some things in common.
* user accounts, with at least one priviliged account, to admin the sites.
* other common functionality, like validators, an iterator, blah blah.
(a quite stripped down list :wink:)

Application examples that are supposed to work standalone or as sisters in the same site:
* news system
* todo list
* e-learning

Now I want to make these modules optional, in the way that if they don't exist in the source tree, they are disabled and if they exist, they can be enabled and configured through browser by admin.

Anyone with experience?
Is this stupid?
Any arguments against building this kind of complex system?

If you think it is an idea worth its development time, how would you make these modules loadable?

I think of a core library containing everything needed to serve modules with user accounts, validation routines, template engine and such.

Then these optional modules reside in a subdirectory called modules, and all these have some kind of activation routine callable by admin that create db tables and such. Modules can depend on each other or have functionality missing if a specific module is not there.

A "registry" in the core library keeps track of these modules and interlock by dependencies and other appropriate things.

You might think I am not really sure about how I would like to do it... That's exactly the case.
I have realised that it'll take som clever brains to make this work and make it work good AND developed within reasonable time.
So, please tell me if you think this is a too ambitious project model or if you have opinions on the implementation draft.

(And oh! I am alone developing this.)
Gen-ik
DevNet Resident
Posts: 1059
Joined: Mon Aug 12, 2002 7:08 pm
Location: London. UK.

Post by Gen-ik »

Sounds like your average modern community website to me.

One Module per PHP page.
Check if modules exist using file_exists().
Use require_once() to load in any module related functions.

There are loads of different ways of doing what you want to do.
User avatar
Heavy
Forum Contributor
Posts: 478
Joined: Sun Sep 22, 2002 7:36 am
Location: Viksjöfors, Hälsingland, Sweden
Contact:

Post by Heavy »

Gen-ik wrote:One Module per PHP page.
Hmmm.. Using front controllers sounds cluttery(*), but since most pages I have written using my template engine are quite small, < 100 lines, maybe It's a good idea.

I'd love more opinions on this.

In the mean time, I'll be thinking using pen and paper for a while... :wink:


* I have done that before, but at that time, I didn't do OOP at all and had the design mixed up with business php so files went biiiiig, and pretty unmainainable.
User avatar
Heavy
Forum Contributor
Posts: 478
Joined: Sun Sep 22, 2002 7:36 am
Location: Viksjöfors, Hälsingland, Sweden
Contact:

Post by Heavy »

Like said here:
viewtopic.php?p=68576#68576
McGruff wrote:They are criticised on grounds of speed but I think it is possible to write a zippy controller. Command hierarchies & lengthy switch cases can be slow - so don't use them. Instead, a chain of includes and a script naming convention seems to work very well with no noticable, real-world speed penalty.
If I stick to short switches and conditional use of includes, it might be quite easy to read and understand, which is highest priority in most cases.
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

Heavy wrote: Now I want to make these modules optional, in the way that if they don't exist in the source tree, they are disabled and if they exist, they can be enabled and configured through browser by admin.
An option to turn a module off just means not linking to it anywhere ie the admin script would adjust whatever site nav you have to add/remove links to - say - a news area.

Are you using OOP? Personally I wouldn't attempt a complex project like this without it.

I'm developing my own front controller at the moment which I'm approaching from the point of view of page layout blocks - header, sidebar, main content area etc.

Each block has its own object script (and possibly helper objects if needed) which simply create a bunch of page vars. No html at this stage in order to support multiple output options.

An HttpRequest object grabs the query string and translates it into $request_args.

A RequestManager loads up some stuff common to all pages (sessions, authentication, etc) and calls a RequestHandler for the page (individual handler per page type).

Handlers set meta data describing the block object scripts used to build the page, and how they will be presented.

A BlockManager object (called by RequestManager) loads the block objects required to build the requested page (receiving the list of blocks from the RequestHandler).

Block objects create page vars data structures and add these to a PresentationRequest object - another data structure. Block presentation meta data (such as sub-templates) was previously sent to PresentationRequest by the RequestHandler.

Finally, RequestManager calls a Presenter to print the page, using the info in PresentationRequest.

It's still experimental but seems to be working well.

UML is essential to figure out a design like this. Info on this and OOP design can be found at phppatterns.com
User avatar
Heavy
Forum Contributor
Posts: 478
Joined: Sun Sep 22, 2002 7:36 am
Location: Viksjöfors, Hälsingland, Sweden
Contact:

Post by Heavy »

McGruff wrote:An option to turn a module off just means not linking to it anywhere ie the admin script would adjust whatever site nav you have to add/remove links to - say - a news area.
Yep.
McGruff wrote:Are you using OOP?
Definitely.
I am reusing som classes I've developed during this fall.
McGruff wrote:I'm developing my own front controller at the moment which I'm approaching from the point of view of page layout blocks - header, sidebar, main content area etc.
Me too. First I was aiming for an enter page and once you were logged in you would have access to all the modules you are authorised to use. But I trashed that Idea... What is the use of a news system you would have to "enter"...
Now, I am going for having a site frontpage which deliver news and links to other modules based on whether they are installed, configured, enabled and you hav access permissions to them.
McGruff wrote:Each block has its own object script (and possibly helper objects if needed) which simply create a bunch of page vars. No html at this stage in order to support multiple output options.
My philosophy as well, except for that I plan to use a directory for every module. Depending on module granularity, the site might get cluttered with files if all files are in the same place.
Modules should have a common interface and that includes files that provide similar functionality, yet regarding different areas of operation.
For instance, a transaction class containing database functionality specific to the module can be called transactions.php. It can have child classes, one for each db type. For example transactions_mysql_innodb.php, transactions_mssql.php, transactions_pgsql.php

These can be called the same whatever module we are referring to. If the module uses transactions of course...

Someone might complain about multiple files with identical names, but I don't think that is a problem.
McGruff wrote:An HttpRequest object grabs the query string and translates it into $request_args.
Have that from an earlier project
McGruff wrote:A RequestManager loads up some stuff common to all pages (sessions, authentication, etc) and calls a RequestHandler for the page (individual handler per page type).

Handlers set meta data describing the block object scripts used to build the page, and how they will be presented.

A BlockManager object (called by RequestManager) loads the block objects required to build the requested page (receiving the list of blocks from the RequestHandler).
The RequestManager I understand. Can you provide an example of a block handler setting meta data? (not necessarily code. Please describe it.)
McGruff wrote:Block objects create page vars data structures and add these to a PresentationRequest object - another data structure. Block presentation meta data (such as sub-templates) was previously sent to PresentationRequest by the RequestHandler.

Finally, RequestManager calls a Presenter to print the page, using the info in PresentationRequest.

It's still experimental but seems to be working well.
Do you think I repeat myself if I say that I have the same philosophy here too?
McGruff wrote:UML is essential to figure out a design like this. Info on this and OOP design can be found at phppatterns.com
Didn't know there is a standard for how to draw lines. Beautiful! Thanks!
That site is a nice resource.

I think what you call BlockManagers are what is missing in my master plan.
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

I plan to use a directory for every module. Depending on module granularity, the site might get cluttered with files if all files are in the same place.
Yeah. I find I spend a lot of time working out an intuitive directory structure and var / fn names. Helps enormously in the long run.
For instance, a transaction class containing database functionality specific to the module can be called transactions.php.
Eclipse http://www.students.cs.uu.nl/people/voo ... /index.php is worth a look for something ready-rolled - or just as an example of good OOP design. Working out your own is also a worthwhile exercise if you've got the time.
The RequestManager I understand. Can you provide an example of a block handler setting meta data? (not necessarily code. Please describe it.)
I think what you call BlockManagers are what is missing in my master plan.
BlockManger loads the objects used to create page vars for each page layout block. It's not tied to any particular page at all and so needs to be given a list of objects to load ($block_meta). This is defined in a RequestHandler (individual handlers per page type).

Block object meta data (I'm self-taught so I hope I'm using that term properly) is an array:

$block_meta[0]['script'] = 'path/to/file.php';
$block_meta[0]['class'] = 'MyClass';
$block_meta[1]['script'] = 'path/to/file2.php';
$block_meta[1]['class'] = 'MyClass2';
etc - an element for each block object to be loaded for this request.

BlockManager loops through the array loading each block object in order. Often the order isn't important - would only matter if block objects need to access each others vars (they can't access a var which hasn't yet been defined - obviously).

In BlockManager I use this to iterate through the array:

Code: Select all

<?php

    function loadBlockScripts()
    {        
        // array_shift returns null if array is empty or not an array
        while(!is_null($block = array_shift($this->block_meta)))
        {
            include($block['script']);
            ${$block['class']} =& new $block['class']($this, $block);
            ${$block['class']}->setPageVars();
        }
    }


?>
Knocking an element off the array each loop allows you to do a neat trick: the block objects can redefine the $block_meta array while it is being processed by BlockManager - even reloading themselves for another go. I haven't actually found a use for this yet but it would allow the script to dynamically reprogram itself depending on the results of each block object's execution. You'd have to be careful not to get stuck in infinite loops though.

The block objects might in turn load various helper objects to define the content for this block. For example, a ForumsList block object would use Board, BoardsList and Forum to build a list of forums. Block objects relate to page layout areas - the kind of thing you'd stick in a div with an id.

As well as $block_meta, a request handler also defines some presentation meta data - general stuff such as the Presenter to use, as well as an array of block-specific data:

$this->presentation_blocks['MyClass']['template'] = 'template_name.htm';
$this->presentation_blocks['MyClass']['print_order'] = 1;
$this->presentation_blocks['MyClass']['css_id'] = $this->css_id; // the block's div id

This is set as a PresentationRequest property. Later, each block object will add page vars data structures to the appropriate key:

$this->presentation_blocks['MyClass']['page_vars'] =& $page_vars;

Now PresentationRequest has all the info needed to output each page layout block. This is passed to a Presenter. Presentationrequest is just a data store - it's the Presenters which actually print the page.

So, request handlers provide a single location to define the page structure and presentation using the $block_meta and $presentation_blocks arrays.

Usually that's all they do - but if any request processing is required (ie anything in addition to building a page to send to the browser) it's managed by the handler.

Form submission processing for example would be carried out by a request handler. The POST array would be checked and either the data would be processed prior to defining meta data for a "success" page, or (if required data is missing) the meta data used to build the form page would be set. The http request would also be redefined in the latter case to provide all the $request_args required by the form object - including a $message "please enter a title" or whatever, and any previously entered field values.

Note that the same block object page vars can be output in different templates & css id's on different page types - the page's request handler is free to choose. It would also be easy to create a bunch of xml handlers and an xml presenter - and so on.

After several revisions in recent weeks, I think I'm getting close to the final design but it is still experimental and I wouldn't want to put this forward as "the" way to do it.

Will be away for a week from tomorrow but will try to get online if I can.
Post Reply