Example #1
0
/**
 * URL path relative to current request path.
 * Note: Designed for use with controllers.
 *
 *		Usage example:
 *			{url controller="blogs"} # /blogs
 *			{url controller="blogs" action="list"} # /blogs/list
 *			{url controller="blogs" action="edit" id=$blog_id} # /blogs/edit/123
 */
function url($params)
{
    // Controller path and name.
    $controller_path = Request::$controller->request->path;
    $controller_name = Request::$controller->request->controller;
    if (is_string($params)) {
        $path = preg_replace("/[\\?\\&].*/", '', $params);
    } else {
        if (is_array($params)) {
            $controller = $params['controller'] ? $params['controller'] : $controller_path . $controller_name;
            if ($controller[0] !== '/') {
                $controller = $controller_path ? "{$controller_path}{$controller}" : "/{$controller}";
            }
            if ($params['action'] && $params['action'] !== Request::$config->app['default_action']) {
                $action = $params['action'];
            }
            // Absolute path (default controller).
            if ($params['absolute']) {
                $action = $action ?: Request::$config->app['default_action'];
            }
            // Unset all expected params, leaving action args.
            unset($params['controller']);
            unset($params['action']);
            unset($params['absolute']);
            // If other params have been passed, try to align them with action args.
            $parts = Controller::get_parts($controller, $controller_path);
            if (count($params) && @(include_once APP_ROOT . "app/controllers{$parts['path']}{$parts['class']}.php")) {
                $method_name = strtolower(str_replace('-', '_', $action ? $action : Request::$config->app['default_action']));
                if (method_exists($parts['class'], $method_name) && ($method = new ReflectionMethod($parts['class'], $method_name))) {
                    $args = $method->getParameters();
                    $arg_string = '';
                    $skipped = 1;
                    foreach ($args as $num => $arg) {
                        if (isset($params[$arg->name])) {
                            $arg_string .= str_repeat('/', $skipped);
                            $arg_string .= $params[$arg->name];
                            $skipped = 1;
                        } else {
                            $skipped++;
                        }
                    }
                    if ($arg_string) {
                        $action .= $action ? $arg_string : Request::$config->app['default_action'] . $arg_string;
                    }
                }
            }
            if (!$arg_string && $controller == Request::$config->app['default_controller'] && $action == Request::$config->app['default_action']) {
                $path = '/';
            } else {
                $path = $action ? "{$controller}/{$action}" : $controller;
            }
        }
    }
    return $path;
}
Example #2
0
 /**
  * Dispatch a controller/request.
  */
 static function dispatch($params, $render = true)
 {
     $config = self::$config;
     $uri = url($params);
     // Trigger dispatch event.
     $uri = trigger('request', 'dispatch', $uri, $config);
     // Match domain route?
     if ($config->domain_routes) {
         if ($_SERVER['HTTP_HOST']) {
             foreach ((array) $config->domain_routes as $name => $domain_match) {
                 if (preg_match('/' . $domain_match . '$/', $_SERVER['HTTP_HOST'])) {
                     $domain = $name;
                     break;
                 }
             }
         } else {
             if (preg_match('/^\\/?([^\\:\\/]+)[\\:\\/]+/', $uri, $match)) {
                 $name = $match[1];
                 if ($config->domain_routes[$name]) {
                     $uri = preg_replace('/\\/?' . $name . '[\\:\\/]+/', '/', $uri);
                     $domain = $name;
                 }
             }
         }
     }
     // Match URI to a route.
     foreach ($config->routes as $route) {
         if (!is_array($route)) {
             throw new Exception('App route is busted');
         }
         $route_uri = $route_exp = array_shift($route);
         // Limit route by domain?
         if ($route['domain'] && $domain != $route['domain']) {
             continue;
         }
         // Named binds?
         if (strpos($route_uri, ':') !== false) {
             // Create a regular expression to check for valid route, start with controller (special).
             $route_exp = str_replace(":controller", '?(.*)', $route_uri);
             // Bind requirements.
             foreach ((array) $route['requirements'] as $bind_name => $exp) {
                 $route_exp = preg_replace("/:{$bind_name}/", "({$exp})", $route_exp);
             }
             // All other binds.
             $route_exp = preg_replace("/:([^\\/]+)/", '([^/]+)', $route_exp);
         }
         // Separator.
         $route_exp = str_replace('/', '\\/', $route_exp);
         // Wildcards.
         $route_exp = str_replace('/*', "/?(.*)", $route_exp);
         // Check if URI matches route.
         if (preg_match("/^{$route_exp}\$/", $uri)) {
             // Find controller in URI?
             if (strpos($route_uri, ":controller") !== false) {
                 $controller_exp = str_replace(":controller", '?(.*)', $route_uri);
                 $controller_exp = str_replace('/', '\\/', preg_replace("/:([^\\/]+)/", '?[^/]*', $controller_exp));
                 if (preg_match_all("/^{$controller_exp}/", $uri, $controller_matches)) {
                     $controller_test_path = $controller_matches[1][0];
                 }
             }
             // Make sure we have a place to start with the controller path.
             if (!$controller_test_path) {
                 $controller_test_path = $route['controller'];
             }
             $uri_parts = explode('/', trim($controller_test_path, '/'));
             // Test URI parts until we find an existing controller (start with domain route name).
             $test_path = $domain ? "/{$domain}" : '';
             for ($i = 0; $i < count($uri_parts); $i++) {
                 $test_path .= '/' . $uri_parts[$i];
                 // Try to match dir default first.
                 $parts = Controller::get_parts("{$test_path}", $controller_path);
                 if (is_dir(APP_ROOT . "app/controllers{$test_path}")) {
                     $parts_dir = Controller::get_parts("{$test_path}/", $controller_path);
                     if (is_file(APP_ROOT . "app/controllers{$parts_dir['path']}{$parts_dir['class']}.php")) {
                         $parts = $parts_dir;
                         $found = true;
                     }
                 }
                 if ($found || is_file(APP_ROOT . "app/controllers{$parts['path']}{$parts['class']}.php")) {
                     // Controller found.
                     $controller = $parts;
                     $controller_path = $controller['path'];
                     $controller_name = $controller['name'];
                     $controller_class = $controller['class'];
                     // Remove domain route name from route uri?
                     if ($domain) {
                         $controller_is_default = $domain == $controller_name;
                         $replace = preg_replace('/^\\/' . $domain . '/', '', $test_path);
                     } else {
                         $replace = $test_path;
                     }
                     // Rewrite route uri for the rest of the binds.
                     $route_uri = str_replace('/:controller', $replace, $route_uri);
                     break;
                 }
                 // If nothing was found, try the default controller.
                 if ($domain) {
                     if ($i + 1 == count($uri_parts) && $uri_parts[$i] !== $domain) {
                         $test_path = '';
                         $uri_parts[] = $domain;
                     }
                 } else {
                     if ($i + 1 == count($uri_parts) && $uri_parts[$i] !== $config->app['default_controller']) {
                         $uri_parts[] = $config->app['default_controller'];
                     }
                 }
             }
             // Output?
             if (preg_match('/\\/[^\\/]+\\.([^\\/]+)$/', $uri, $output_matches)) {
                 $output = $output_matches[1];
                 $uri = substr($uri, 0, strrpos($uri, '.'));
             }
             // Find values for all other URI binds.
             $binds = $route;
             if (preg_match_all("/:([^\\/]+)/", $route_uri, $bind_matches) || strpos($route_uri, '*') !== false) {
                 $route_exp = $route_uri;
                 // Bind requirements.
                 foreach ((array) $route['requirements'] as $bind_name => $exp) {
                     $route_exp = preg_replace("/:{$bind_name}/", "?({$exp})", $route_exp);
                 }
                 // All other binds.
                 $route_exp = str_replace('/', '\\/', preg_replace("/:([^\\/]+)/", '?([^/]*)', $route_exp));
                 // Wildcards.
                 $route_exp = str_replace('/*', "/?(.*)", $route_exp);
                 // Pull bind values out of URI.
                 if (preg_match_all("/^{$route_exp}/", $uri, $value_matches)) {
                     foreach ((array) $bind_matches[1] as $key => $bind_name) {
                         $binds[$bind_name] = $value_matches[$key + 1][0];
                         unset($value_matches[$key + 1]);
                     }
                     // Remaining URI.
                     if ($end_value = array_pop($value_matches)) {
                         $uri_remaining = "/{$end_value[0]}";
                     }
                 }
             }
             // Action bind?
             $action = $binds['action'];
             // View bind?
             $view = $binds['view'];
             // Unset special parameters.
             unset($binds['controller']);
             unset($binds['action']);
             unset($binds['requirements']);
             unset($binds['view']);
             // Check if we have binds left to match to action arguments.
             if (count($binds) && $controller && $action && @(include_once APP_ROOT . "app/controllers{$controller_path}{$controller_class}.php")) {
                 list($method_name) = explode('.', underscore($action));
                 if (method_exists($controller_class, $method_name) && ($method = new ReflectionMethod($controller_class, $method_name))) {
                     $args = $method->getParameters();
                     $arg_string = '';
                     $skipped = 1;
                     foreach ($args as $num => $arg) {
                         if (isset($binds[$arg->name])) {
                             $arg_string .= str_repeat('/', $skipped);
                             $arg_string .= $binds[$arg->name];
                             $skipped = 1;
                         } else {
                             $skipped++;
                         }
                     }
                 }
             } else {
                 $arg_string = preg_replace("/^{$route_exp}/", '', $uri);
             }
             // Create action arguments array for action call.
             if ($arg_string . $uri_remaining != '/') {
                 $args = explode('/', substr($arg_string . $uri_remaining, 1));
             }
             break;
         }
     }
     // Controller route defined.
     $route = array('domain' => $domain, 'path' => $controller_path ?: "/{$domain}/", 'controller' => $controller_name, 'action' => $action, 'output' => $output, 'args' => $args);
     // Controller found?
     if ($controller) {
         // Require and create controller.
         require_once APP_ROOT . "app/controllers{$controller_path}{$controller_class}.php";
     } else {
         // Determine view by bind or uri.
         $route['view'] = $view ?: $uri;
         // AppController or Controller.
         $controller_class = class_exists('AppController') ? 'AppController' : 'Controller';
     }
     // Create controller instance.
     $controller = new $controller_class($route);
     // Push controller onto stack.
     self::$controller =& $controller;
     self::$stack[] = self::$controller;
     // Trigger new controller event.
     $controller = trigger('controller', 'new', $controller);
     // Invoke controller action (method).
     if (method_exists($controller, $controller->request->action)) {
         $result = call_user_func_array(array(&$controller, $controller->request->action), (array) $controller->request->args);
     } else {
         if (method_exists($controller, '__default')) {
             $result = call_user_func_array(array(&$controller, '__default'), (array) $controller->request->args);
         }
     }
     // Returned an HTTP status code?
     if (is_int($result)) {
         // Redirection?
         if ($result >= 300 && $result < 400) {
             exit;
         } else {
             if ($result >= 400 && $result < 600) {
                 throw new Exception("{$controller_class}::{$action}() returned code {$result}", $result);
             }
         }
     } elseif ($result) {
         print $result;
         exit;
     }
     // Render output?
     if ($render) {
         $controller->render();
     }
     // Pop controller, return it.
     return array_pop(self::$stack);
 }