ice framework documentation ice doc v1.10.1
Class Ice Mvc

Router

    
namespace Ice\Mvc;

use Ice\Di;
use Ice\Exception;

/**
 * Router is the standard framework router. Routing is the process of taking a URI endpoint and decomposing it into
 * parameters to determine which module, controller, and action of that controller should receive the request.
 *
 * @package     Ice/Router
 * @category    Component
 * @author      Ice Team
 * @copyright   (c) 2014-2023 Ice Team
 * @license     http://iceframework.org/license
 */
class Router
{
    // list of route objects
    protected routes = [] { get };

    // the name of current matched route after handle()
    protected route = "default";

    protected method { get };
    protected module { get };
    protected handler { get };
    protected action { get };
    protected params = [] { get };
    protected silent = false { get, set };

    // default module
    protected defaultModule = "default" { get, set };

    // default handler
    protected defaultHandler = "index" { get, set };

    // default action
    protected defaultAction = "index" { get, set };

    /**
     * Stores a named route and returns it.
     *
     * 

     *     $router->addRoute("default", "[/{controller}[/{action}[/{id}]]]")
     *         ->setDefaults(["controller" => "hello"]);
     * 
* * @param string route name * @param string URI pattern * @param array regex patterns for route keys * @param mix method Request method limitation, * for no limit or an array of methods * @return object self */ public function addRoute(string name, string uri, array regex = null, var method = "*") { let this->routes[name] = new Route(uri, regex, method); return this->routes[name]; } /** * Retrieves a named route or the current matched route. * *

     *     $route = $router->getRoute("default");
     * 
* * @param string route name * @return Route|null */ public function getRoute(string name = null) { var n = name; if n === null { let n = this->route; } return isset this->routes[n] ? this->routes[n] : null; } /** * Get the name of a route. * * @param object Route instance * @return string */ public function getRouteName( route) { return array_search(route, this->routes); } /** * Saves or loads the route cache. * *

     *     if (! $router->cache()) {
     *         // set routes
     *         $router->addRoute("default", "[/{controller}[/{action}[/{id}]]]");
     *         // cache routes
     *         $router->cache($filePath);
     *     }
     * 
* * @param string file Cache the current routes to the file * @return self|boolean when saving routes or loading routes */ public function cache(string file = null) { if file { // Cache all defined routes file_put_contents(file, "routes, true) . ";"); return true; } if file_exists(file) { let this->routes = require file; // Routes were cached return true; } // Routes were not cached return false; } /** * Set defaults values * *

     *     $route->defaults(["controller" => "hello", "action" => "world"]);
     * 
* * @param array defaults values * @return self */ public function defaults(array! defaults) { var module, handler, action; if fetch module, defaults["module"] { let this->defaultModule = module; } if fetch handler, defaults["controller"] { let this->defaultHandler = handler; } if fetch action, defaults["action"] { let this->defaultAction = action; } return this; } /** * Set an array of route rules. * httpMethod: *|null - no limit, GET, POST, PUT or PATCH * URI pattern: [] wrap for optional, {} wrap for regex placeholder key * regex: an associate array placeholder key and regex limitation pattern * defaults: default options for the module, handler and action * *

     *     // the rule format: ['name' => ["httpMethod", "URI pattern", "regex", "defaults"]]
     *     $route->setRoutes([
     *         ["default" => ["POST", "/{controller}[.ext]", ["controller" => "[a-z]+", "ext" => "(?:htm|html)"]]]
     *     ]);
     * 
* * @param array routes Route rules * @return self */ public function setRoutes(array! routes = null) { var name, option, route, regex, defaults; if empty routes { // Set default routes let routes = [ ["*", "[/{controller}[/{action}[/{id}[/{param}]]]]", ["controller":"\\w+", "action":"\\w+"]] ]; } for name, option in routes { if !fetch regex, option[2] { let regex = []; } let route = this->addRoute(name, option[1], regex, option[0]); if fetch defaults, option[3] && typeof defaults == "array" { route->setDefaults(defaults); } } return this; } /** * Handles routing information. * * @param string method * @param string uri * @return mixed */ public function handle(string method = null, string uri = null) { var name, route, params, matches, response; // Remove trailing slashes from the URI let uri = uri == "/" ? "/" : rtrim(uri, "/"), matches = null; if !this->routes { // Set default routes this->setRoutes(); } for name, route in this->routes { let params = route->matches(uri, method); if !empty params { let this->route = name, this->method = method; if isset params["module"] { let this->module = params["module"]; } else { let this->module = this->defaultModule; } if isset params["controller"] { let this->handler = params["controller"]; } else { let this->handler = this->defaultHandler; } if isset params["action"] { let this->action = params["action"]; } else { let this->action = this->defaultAction; } // These are accessible as public vars and can be overloaded unset params["controller"]; unset params["action"]; unset params["module"]; // Params cannot be changed once matched let this->params = params; return [ "module": this->module, "handler": this->handler, "action": this->action, "params": this->params ]; } elseif params === false { // method not allowed let matches = false; } } if this->silent { // 404 Not Found, 405 Method Not Allowed let response = Di::$fetch()->get("response"), matches = matches === null ? 404 : 405; return response->setStatus(matches) ->setBody(response->getMessage(matches)); } throw new Exception([ matches === null ? "Unable to find a route to match the URI: %s" : "Request method not supported by that resource: %s", uri ]); } /** * Get route matched by uri and method. * * @param string uri * @param string method * @return Route|false|null */ public function match(string uri = null, string method = null) { var route, params, matches; // Remove trailing slashes from the URI let uri = uri == "/" ? "/" : rtrim(uri, "/"), matches = null; for route in this->routes { let params = route->matches(uri, method); if !empty params { return route; } elseif params === false { // method not allowed let matches = false; } } return matches; } /** * Generates a URI based on the parameters given. (AKA. reverse route). * *

     *     $uri = $router->uri(["controller" => "blog", "action" => "post", "param" => 10]);
     * 
* * @param array URI parameters * @param string method * @return string|null */ public function uri(array! params, string method = "*") { var route, uri; for route in this->routes { let uri = route->uri(params); if uri !== false && route->checkMethod(method) { return uri; } } return null; } }