简体   繁体   中英

Most efficient way to route urls in a PHP mvc?

I'm developing a simple php mvc that'll do the bare minimum but work how I need it too, it's my first time using an mvc approach over prodcedural so I'm learning as I go ..

While developing I've accidentally created it in a strange sort of style, currently the main .htaccess contains pretty much all of the physical rewrites, for example the forum is:

RewriteRule ^forum/([a-zA-Z0-9_]+)_([0-9]+)/$                    index.php?controller=forum&method=showThread&urlTitle=$1&threadId=$2 [L] 
RewriteRule ^forum/([a-zA-Z0-9_]+)_([0-9]+)/all/([0-9]+)$        index.php?controller=forum&action=showThread&urlTitle=$1&threadId=$2&page=$3 [L]

How it works at the moment is that all urls are directed to index.php and it then takes which controller and method to use from the url using:

index.php

$actionName = $_GET['action'];
$controllerName = ucfirst(strtolower($_GET['type'])).'controller';

$controller = new $controllerName;
$controller->$actionName();

controller/forumcontroller.php

class forumcontroller{

    function showThread() {

        $thread = new Thread($_GET['threadId'], $_GET['uriTitle']); 
        require "templates/thread.php";
    }

but this means it's possible for users to go to locations I don't want them to have access too, such as:

/public_html/templates/index.php

What I think I need?

I think instead the main .htaccess should look something like this?

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]

and then in index.php you'd use something like:

$url = explode("/", `$_SERVER['QUERY_STRING']);`

$controller = $url[0];   //Returns "forum"
$data = $url[1];         //Returns the forum title and id

but with this approach I don't understand how you call the action inside the controller with just the data?

wouldn't you have to do something like:

 if(!$data)
     $controller->loadForum();
 elseif($data)
     $controller->loadForumThread($data);

Conclusion

I'm just not understanding how to best do the routing for a site that has a lot of seo friendly urls in different formats, I understand how an mvc should work but I'm struggling to grasp the routing part and all the examples I come across seem extremely complex!

I'm really struggling to see how to code the .htaccess and controllers to handle lots of urls in different formats, like this:

domain.com
domain.com/uploads
domain.com/profiles/username
domain.com/messages/inbox
domain.com/messages/createnew/userId
domain.com/forum/all/2
domain.com/forum/title_1/
domain.com/forum/title_1/all/3

Here is an approach that is similar to your second .htaccess example.

$request = explode('/', substr($_SERVER['REQUEST_URI'], 1));
// Clean request array of empty elements
foreach($request as $k => $v)
    // Clear any empty elements
    if(!$v) unset($request[$k]);
$request = array_values($request);  // Renumber array keys

This gives a numerically indexed array representing the requested URI. The application can assume that the first value in the request is the name of the controller:

if(count($this->request) == 0) 
    $request[] = 'DefaultController';  // Responsible for homepage
$this->controller = new $request[0]( $request );

I also pass a $context variable to the controller constructor, but that's out of scope for this question (it is responsible for database connection, current user data and session data).

After that, it simply dispatches the request: $this->controller->dispatch()

Inside of the dispatch method, the controllers themselves are aware of the request array. In your URL list, for instance, let's look at the third example: domain.com/profiles/username :

The controller would be named 'Profiles':

class Profiles {
    private $request, $context;
    public function __construct($request, $context) {
        $this->request = $request;
        $this->context = $context;
    }

    public function dispatch() {
        if(count($this->request) == 2 && $this->request[1] == 'username') {
            // Load data from model for the requested username ($this->request[1])

            // Show View
        }
    }
}

There's better ways that you can map request vectors to actions, but hopefully you get the jist.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM