1

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;
  }
}
tereško
  • 58,060
  • 25
  • 98
  • 150
Alchalade
  • 307
  • 1
  • 5
  • 14

2 Answers2

2

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"
}
svgrafov
  • 1,970
  • 4
  • 16
  • 32
  • Thank you for the answer but it doesn't help(solve the problem completely) in my case. Url :http://localhost:8080/ut/User/getUser/1 Output :array(4) { ["scheme"]=> string(4) "http" ["host"]=> string(9) "localhost" ["port"]=> int(8080) ["path"]=> string(18) "/ut/User/getUser/1" } but I can use it for the first part of parsing (remove base url from the reuqest path. – Alchalade Nov 09 '17 at 11:09
  • done, I've add example request and the current output to the question – Alchalade Nov 09 '17 at 11:19
1

First of all, you don't need to parse the full URL, because you can retrieve the user's call
in $_SERVER['REQUEST_URI'] ... but I guess this is not so elegant.

As for splitting the that URI path, you should actually be using a regexp. In your specific example the regular expression would be:
'#^/ut/(?P<controller>[\w]+)/(?P<method>[\w]+)/(?P<id>[\d]+)$#i'

Live sample: here

You can read some more about how to make a routing code here, but unless you are doing this as learning experience, you probably should instead use an existing library, like FastRoute or the Symfony's standalone router.

tereško
  • 58,060
  • 25
  • 98
  • 150