Search code examples
phpurl-routing

Best way to parse request into Controller / Function / Parameters


I started to experiment with my own MVC.

My goal was just to implement the controllers models and views and relate them but unfortunately, it goes in a (little) framework direction.

I have a base index.php in the root folder which is responsible for routing. (determine which controller should be created, which function is going to be called on the newly created controller instance etc.)

I'm parsing the controller,function and the variables directly from the url (like codeigniter is doing) ex :http://baseurl/index.php{router} /User{controller}/get{function to be called}/1{variable-0}/desc{variable-1} instead of using get method to identify them (like ?c=mainController&f=function_to_be_called).

My question is (based on what I'm doing), is there another(better way) to achieve the same result?

Edit:
Example request:http://localhost:8080/ut/User/getUser/1

Output : array(3) { ["controller"]=> string(4) "User" ["function"]=> string(7) "getUser" ["variables"]=> array(1) { [2]=> string(1) "1" } }

Thank you for your attention.

<?php

namespace System;

class UrlParser
{
public static function parseRequest(string $url):?array
{
    //default destination if nothing matches
    $destination = '404';//self::$routes['index'];

    //the order: controller to be loaded, function to be called and parameters etc...
    $hierarchical_call = array();
    //remove www : [I know its not generic]
    //TODO: check base url if it contains www, don't remove www
    $url = str_replace('www', '', $url);
    // check for a trailer slash, if not add it
    $url = substr($url, strlen($url) - 1, 1) === '/' ? $url : $url . '/';

    // split url into base url and rest
    $url_parts = explode(baseurl, $url);
    //url has more content
    if (count($url_parts) > 1) {
        $rest_url = $url_parts[1];

        /*add leading slash for regex, it is easier to get the string between two slashed insteadof [A-Z]*/
        $rest_url = substr($rest_url, 0, 1) === '/' ? $rest_url : '/' . $rest_url;

        /*
         * use regex to get the first part which is between / and /
         * if it is index.php than check if url parts has any other request
         */
        $pattern = '/[a-zA-Z0-9_\.]+/';
        preg_match_all($pattern, $rest_url, $request_parts, PREG_SET_ORDER);
        /*
         * PREG_PATTERN_ORDER
         * Orders results so that $matches[0] is an array of full pattern matches,
         * $matches[1] is an array of strings matched by the first parenthesized subpattern, and so on.
         */
        for ($i = 0; $i < count($request_parts); $i += 1) {
            //the requested file is determined add the remaining parts to it
            if (strlen($request_parts[$i][0]) > 0 && $request_parts[$i][0] !== 'index.php') {
                $hierarchical_call[] = $request_parts[$i][0];
            }
        }
    }
    return $hierarchical_call;
  }
}

Solution

  • Php has built-in function for that - parse_url.

    $url = 'http://localhost:8080/ut/User/getUser/1';
    $parsed = parse_url($url); 
    var_dump($parsed);
    
    
    
    array(4) { 
       ["scheme"]=> string(4) "http" 
       ["host"]=> string(9) "localhost"
       ["port"]=> int(8080)
       ["path"]=> string(18) "/ut/User/getUser/1"
    }
    

    After that explode path:

    $route = explode("/", $parsed['path']);
    var_dump($route);
    
    
    
    array(5) {
        [0]=> string(0) "" 
        [1]=> string(2) "ut"
        [2]=> string(4) "User"
        [3]=> string(7) "getUser"
        [4]=> string(1) "1"
    }