0

I was wondering if anyone can me me with my php script, I am trying to make clean URLs like this, without using any regex.

Controller/Method/arg1/arg2/arg3

So far I have it working good but I can not get it to work with the arguments in the URL. If anyone can get this script to work with the arguments in the URL it would help me a lot. My current router can only map controller and method and the args will have to be after a ? but I want to have it work after / like the clean URL example i posted. thank you.

$router = new Router();
$router->add('/', 'HomeController::IndexAction');
$router->add('/edit', 'HomeController::EditAction');

$response = $router->dispatch(new Request);

print_r($response);

class Router
{
    private $routes = array();

    public function add($path, $controller)
    {
        $this->routes[$path] = $controller;
    }

    public function match($uri)
    {   
        if(array_key_exists($uri, $this->routes)) {
            return $this->routes[$uri];
        }
    }

    public function dispatch(Request $request)
    {
        $route = $this->match($request->getUri());
        if($route) {
            list($controllerName, $method) = explode('::', $route, 2);
            $controller = new $controllerName;

            if(method_exists($controller,$method)) {      
                return $controller->{$method}($request);
            }
        }
        return "Error route not found!";
    }

}

class Request
{
    private $uri;
    private $args = array();

    public function __construct() 
    {
        $scriptName = $_SERVER['SCRIPT_NAME'];
        $uri = $_SERVER['REQUEST_URI'];
        $args = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
        if (strpos($uri, $scriptName) !== false) {
            $path = $scriptName;
        }
        else {
            $path = str_replace('\\', '', dirname($scriptName));
        }
        $uri = substr_replace($uri, '', 0, strlen($path));
        $uri = str_replace('?' . $args, '', $uri);
        $uri = '/' . ltrim($uri, '/');

        $this->uri = $uri;
        $this->args = $args;
    }

    public function getUri()
    {
        return $this->uri;
    }

    public function getArgs()
    {
        return $this->args;
    }
}

class HomeController
{
    public function IndexAction(Request $request)
    {
        return "home controller";
    }

    public function EditAction(Request $request)
    {
        return $request->getArgs();
    }

}
tereško
  • 58,060
  • 25
  • 98
  • 150
Tim98760
  • 7
  • 5

1 Answers1

0

Inspired by Kohana for the <...> thing, here is basic example about how to do what you want.

You may want to modify your add() method to allow parameter (like controller should match only letters, arg1 only numeric and such).

Also, after the route is found, you have to check the controller and the method exists

<?php
$router = new Router();
$router->add('/<controller>/<method>/<arg1>/<arg2>/<arg3>', 'HomeController::IndexAction');
$router->add('/edit', 'HomeController::EditAction');

$response = $router->dispatch(new Request);

print_r($response);

class Router
{
 private $routes = array();
 private $rex_routes = array();

 private $current_route = null;

 public function param($name)
 {
   if (isset($this->current_route[$name]))
    $this->current_route[$name];
 }

 public function add($path, $controller)
 {
  $this->routes[$path] = $controller;
  if (preg_match_all('#<(.*)>#U', $path, $matches))
  {
   $params = $matches[1];
   $rex_route = preg_replace('#<(.*)>#U', '(.*)', $path);
   $this->rex_routes['#'.$rex_route.'#'] = $params;
  }
  $this->routes[$path] = $controller;
 }

 public function match($uri)
 {
  if(array_key_exists($uri, $this->routes)) {
   return $this->routes[$uri];
  }
  else
   foreach($this->rex_routes as $route => $params)
   {
    if (preg_match($route, $uri, $matches))
    {
     array_shift($matches);
     $this->current_route = array_combine($params, $matches);
     return true;
    }
   }
   throw new Exception "$uri does not match<br/>";
 }

 public function dispatch(Request $request)
 {
  $route = $this->match($request->getUri());
  if($route) {
   list($controllerName, $method) = explode('::', $route, 2);
   $controller = new $controllerName;

   if(method_exists($controller,$method)) {      
    return $controller->{$method}($request);
   }
  }
  return "Error route not found!";
 }

}

class Request
{
 private $uri;
 private $args = array();

 public function __construct() 
 {
  $scriptName = $_SERVER['SCRIPT_NAME'];
  $uri = $_SERVER['REQUEST_URI'];
  $args = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
  if (strpos($uri, $scriptName) !== false) {
   $path = $scriptName;
  }
  else {
   $path = str_replace('\\', '', dirname($scriptName));
  }
  $uri = substr_replace($uri, '', 0, strlen($path));
  $uri = str_replace('?' . $args, '', $uri);
  $uri = '/' . ltrim($uri, '/');

  $this->uri = $uri;
  $this->args = $args;
 }

 public function getUri()
 {
  return $this->uri;
 }

 public function getArgs()
 {
  return $this->args;
 }
}

class HomeController
{
 public function IndexAction(Request $request)
 {
  return "home controller";
 }

 public function EditAction(Request $request)
 {
  return $request->getArgs();
 }

}
Asenar
  • 6,732
  • 3
  • 36
  • 49