1) So, the main question is, does something just not look right?
Personally, I see this becoming more complex as your site grows. The MVC structure, as I was taught, to a large extent should be “Set and Forget” - you separate the request handler (controller) from the database requests and the business end (model) and from the display elements (view).
[ Note: You may need other basic aspects. My standard structure includes some basic elements that carry the session through various parts, and also process the fundamental aspects of the site. For example, while models are responsible for the correct database calls as instructed by the controller, there are basic functions in the sql.class.php file that give me a standardized set of methods for making these calls and delivering or caching the results as needed.]
Your submit method is on the right track with this - you are retrieving the controller name from the URI (forums, profiles, etc.). Do you need uri map? I feel that you are creating an unnecessary situation when you have to update this card every time, and not just create a new controller, when you need new functions, and register it in the database. I’m not saying that you did wrong, I just don’t feel that I would have done so.
2) Is there a better way to determine what is in the URI than using a regular expression in an array, as I do, consider it on a site with high traffic?
Control the result (pun intended, as it does the work here). Consider this approach and see how it works for you:
Your index.php file (aka "Main Controller") grabs the URI and explodes the values along the "/" into bits. bit [0] is the identifier of the controller - it says: "I want to use a controller with the name bit [0] => value." This is done as:
require_once( dirname( __FILE__ )."/controllers/".$bit[0]."controller.php" );
Personally, I, being a little neat when it comes to directory structures, I use the [0] bit to identify the directory where controller.php is located, since I may have subcontrollers.
This controller file that I use to parse other bits. For this, I will give an example:
Suppose bit [0] is set to forums. I can pass, if it is set, bit [1] to the switch statement. By default, I always want to list, but I could send it to a "list", "view" or "message" in bit [1]. This will tell me in the controller class which method to call. Then the method will prompt me to invoke the associated model of "forums" if I need to fulfill requests and cache the list of forums, for example.
Extraneous “bits” can do one of two things: they can be passed as simple arguments to the method, what data is requested from the model, or bit [1] can be complex enough to guarantee a subcontroller, and subsequent bits will be passed to this controller to determine the appropriate actions as was done with the forums controller.
Regular expression, being slow, should be avoided whenever possible. Since we may have a URI /forums/view/102305 , we can assume that the forums controller will pass 102305 method associated with the view argument (a method similar to private function displayPost( $id ) , where $id is 102305 ). There is no regex, as we can just blow values along the common expected delimiter.
3) Since everything is routed through the index.php file with this, how will I handle AJAX request processing?
Not very difficult. If the controller is configured for, say, AJAX, you can rebuild the URL and gain direct access to it. You can write exceptions in the .htaccess file ( RewriteRule ^(AJAX)($|/) - [L] ). Or (not an ideal but ill-conceived workaround) is to add ../ to your AJAX URI to return the URI to the root directory - it no longer tries to access index.php , so the rewrite rule does not apply.
Edit
Suppose we use the URI from /forums/id-1234/page-4 for your example. Again, suppose that, as I mentioned above, forums refers to the controller that will be used, and all the rest / limit the arguments (which I like to call "drilling"). So, in our forum manager file (call him forumcontroller.php , we might have something like this (extremely simplified) constructor:
// $registry is a class containing fundamental methods, and is meant to exemplify all // classes tied to the main controller "index.php". Keep in mind, I'm assuming we've // found the right controller by exploding the URI, and passed the remainder as bits // to the constructor. public function __construct( registry $registry ) { $this->registry = $registry; //tying this controller to main controller. // For ease and clarity, we're assuming there no case in which you wouldn't have // bits set. Error checking is easy. $bits = $this->registry->getURLBits; switch( $bits[0] ) { case 'view': $this->showForumEntry( $bits[1], (isset( $bits[2] ) ? $bits[2] : '' ); break; case 'edit': $this->editForumEntry( $bits[1] ); break; case 'post': $this->postForumEntry(); break; default: $this->listForumEntries(); break; } } private function showForumEntry( $thread, $offset ) { // Because you wanted to prepend id to the id element, we can use this for // cheekiness in the query if our DB is well designed. $data = explode('-', $thread); // Select all from forums where id = 1234 $sql = "SELECT * FROM forums WHERE $data[0] = $data[1]"; if( $offset != '' ) { $page = explode('-', $offset); $offset = $page[1] * 25; // Or whatever your max per page is. Make it dynamic. $max = $offset+25; $sql .= " LIMIT $offset, $max"; } // You see where I'm going with this... }
The fact is that you control what is transferred and processed. Manage URIs and you can simplify their handling.
Edit 2 Repeating again, there are several concepts that I think will help you and you should familiarize yourself with:
Check out the "Factory" template here (My $ registry, in its heart, factory set): http://php.net/manual/en/language.oop5.patterns.php
Good breakdown of MVC graphically: http://best-practice-software-engineering.ifs.tuwien.ac.at/patterns/images/mvc3.jpg
More on Factory Methods: http://www.devshed.com/c/a/PHP/Design-Patterns-in-PHP-Factory-Method-and-Abstract-Factory/
Another point, and this is a personal observation after working with Joomla, Drupal, Wordpress and various corporate solutions CMS and BBS. Design exclusively with you. When you start trying to become "something for everyone", you get a lot of extra bloat, which is downloaded from each page and used 1 time out of 100. MVC is a design template, and using it as a template will tell you to get rid of excess in all aspects, including the URI. Handling /controller/arg1-Identifier/arg2-offset not needed, and you can easily get away with /controller/id/offset (e.g. /forums/1234/4 ). If you want to make it SEO friendly, add a thread name and not a tag identifying the identifier (e.g. /forums/1234-This-Is-A-Topic/4 ).
Now let's also point out the obvious about my editing above. This is a controller designed exclusively for a forum item. Each element of your site (for example, forums, galleries, profiles, etc.) must have its own controller. What for? Because everyone does completely different things on their pages. Therefore, use this - you do not need to use a URI card if you understand that you are going to the controller, and the controller delegates the responsibilities of the model to any additional controllers that may be needed.
I really hope this helps.