XMS Router (since version 2.2 above)


Showing 5 from 0 out of

XMS Router is very easy to use and understand: once a request is received by the templating engine (temp.php), the router gets that request and returnsthe source of the application.
This straight forward approach leaves the developer the option not only to load a specific application but create it on the fly.

There is no biult-in rule of the router so, once again the developer is free to decide the way to go. The "logic" of the router is defined in router.xml.

The way it works is: the template engine will build an instance of Route class using router.xml (Route class exetnds awsXML so you have all the tools needed to parse an xml file, router.xml). The template engine will then call init($_SERVER[REQUEST_URI]) method of the Router, and load the application content from it's result. Inside init method, a function created from the text content of first processing instruction underneath router element (root node of router.xml), is called with 3 parameters:
- $router [@class Route],
- $route [@string from request uri]
- $query [@array = $_GET]

Long story, isn't it? Let's make it simple, have a glimpse inside router.xml:

<router>
<!--PARAMETERS: $router, $route,$query-->
<?aws
if ($query["use"]) {
if (!file_exists($query["use"]) || !is_file($query["use"]))
$awsappxmltemplateFile = file_get_contents(AWS_ERROR_404);
else
$awsappxmltemplateFile = file_get_contents($query["use"]);
} else
$awsappxmltemplateFile = file_get_contents(AWS_HOME);
return $awsappxmltemplateFile;?>
</router>

The application source is returned by the code above. This is the code (function) executed by the Router class, inside init method to retreive the xms application  code.

Remember - you are in session so you have access to session, global and any other variables.

This router design provides also a nice way of initializing the applications in a "global" manner. You can use it to connect to databases or any other operation you need in all applications. 

Below I will describe 4 router models,  provided by default with router.xml, inside templates element. You can either use one of these models or make your own but at least you have 4 models to understand what you can do! 

Let's explain a little bit the image above, where you can see the flow of a request sent to the server. In words, that image means: when a request is received, the http server first checks if mod rewrite is enabled.

1. When mode rewrite is enabled, then the server sends all the requests of files and folders that do not exist (see htaccess) to urlhandler.php. The reason is that we need to check if that request comes from the client and is an existing resource that was reffered to, using relative paths. Put it like this:
http://localhost/xmsFolder/this/is/some/fake/path?some=query 
In the url above, we want the first 'fake' folder  to be the name of the application to load, and all other path members to be values to use inside our application.
Using this model it will be difficult for the developer as will always be concerened about how to load the javascript or css or any other resources.
In order to overcome this issue and leave the developer with the logic and application design only, urlhandler.php will check to see if inside that fake path is an existing resource and if it is then will serve it to client side directly!  If the path is nothing more than a fake path, the request is then sent to temp.php in order to be processed by the router!
One other reason I chose this approach, is that I did not wanted to waste time and change from relative to absolute paths, in all applications I built so far with XMS. The third reason is that I just wanted to stay with clean, easy code inside temp.php.

Using mod rewrite we can have the so called "pretty" urls, easy to read!

2. When mod rewrite is disabled, then all request go directly inside temp.php so the router have to be based on the query strings. This is the default functionality that also provides backward compatibility.
 


 SECURITY CONSIDERATIONS:
- do not load applications from $_GET directly: use file_exists or/and is_file functions or point the application to be loaded from a local folder

ROUTER MODEL 1

Content of router.xml: 

<router><?aws // ROUTER MODEL 1 / DEFAULT
//parameters: $router,$route,$query,$accessControl
// default router for backward compatibility
//works both with mod rewrite and without it
//returns the application given in $_GET[use]
if ($query["use"]) {
    if (!file_exists($query["use"]) || !is_file($query["use"]))
	$awsappxmltemplateFile = AWS_ERROR_404;
    else
	$awsappxmltemplateFile = $query["use"];
} else
    $awsappxmltemplateFile = AWS_HOME;

$router->topmost()->TEMPLATE_FILE_SOURCE = $awsappxmltemplateFile; 

if (constant('AWS_USER_ACCESS_DISABLED'))
    return file_get_contents($awsappxmltemplateFile);
else {
    if ($accessControl -> hasAccess($awsappxmltemplateFile))
	return file_get_contents($awsappxmltemplateFile);
    else
	return file_get_contents(AWS_ERROR_403);
}?></router>


This is the default router that comes with XMS. It stands for backward compatibility and relies on getting the path of the application from the $_GET['use'].
An example is: http:// localhost/temp.php?use=templates/myapp.xml

Works both with mod rewrite and without it

ROUTER MODEL 2


Content of router.xml:

<router><route bind="templates/designer.xml"><?aws //do some php stuff here?></route><?aws // ROUTER MODEL 2 / same as model 1 + executes a function //parameters: $router,$route,$query,$accessControl function getRouteCode($el) { foreach ($el->childNodes as $child) if ($child -> nodeType == 7) $toRet = $child -> data; $f = create_function('$el', $toRet); $f($el); } //looks for a route element (inside this file) bounded to above value and if found execute the code inside $router -> q("/router/route[@bind[contains(.,'" . $query["use"] . "')]]") -> each('getRouteCode'); if ($query["use"]) { if (!file_exists($query["use"]) || !is_file($query["use"])) $awsappxmltemplateFile = AWS_ERROR_404; else $awsappxmltemplateFile = $query["use"]; } else $awsappxmltemplateFile = AWS_HOME; $router->topmost()->TEMPLATE_FILE_SOURCE = $awsappxmltemplateFile; if (constant('AWS_USER_ACCESS_DISABLED')) return file_get_contents($awsappxmltemplateFile); else { if ($accessControl -> hasAccess($awsappxmltemplateFile)) return file_get_contents($awsappxmltemplateFile); else return file_get_contents(AWS_ERROR_403); }?></router>

- ROUTER MODEL 2 / same as model 1 + executes a function for each application
- backward compatibility
- works both with mod rewrite and without it
- returns the application given in $query[use] (=$_GET[use])
- additionally executes the function in the bounded "route" element, if found (for application specific initialization)

ROUTER MODEL 3 - mod rewrite only

Content of router.xml:

<router><?aws // ROUTER MODEL 3 //parameters: $router,$route,$query,$accessControl $chain = explode("/", $router -> getPathInfo($route)); $r = "templates/" . $chain[0] . ".xml"; if ($chain[0] != '') { if (!file_exists($r) || !is_file($r)) $router->topmost()->TEMPLATE_FILE_SOURCE = constant("AWS_ERROR_404"); else $router->topmost()->TEMPLATE_FILE_SOURCE = $r; } else $router->topmost()->TEMPLATE_FILE_SOURCE = constant("AWS_HOME"); if (constant('AWS_USER_ACCESS_DISABLED')) return file_get_contents($router->topmost()->TEMPLATE_FILE_SOURCE); else { if ($accessControl -> hasAccess($router->topmost()->TEMPLATE_FILE_SOURCE)) return file_get_contents($router->topmost()->TEMPLATE_FILE_SOURCE); else return file_get_contents(constant("AWS_ERROR_403")); }?></router>

- basic router for mod rewrite
- looks for an application with name templates/.chain[0].xml (where $chain is the path in the SERVER[REQUEST_URI])
- you can call your apps like: http://my-location/appname?some=query

ROUTER MODEL 4 - mod rewrite only

Content of router.xml:


<router><?aws // ROUTER MODEL 4 //parameters: $router,$route,$query,$accessControl // a more advanced router for mod rewrite function getRouteCode($el) { foreach ($el->childNodes as $child) if ($child -> nodeType == 7) $toRet = $child -> data; $f = create_function('$el', $toRet); $f($el); } //extract the first element in route $chain = explode("/", $router -> getPathInfo($route)); //looks for a route element (inside this file) bounded to above value and if found execute the code inside $router -> q("/router/route[@bind[contains(.,'" . $chain[0] . "')]]") -> each('getRouteCode'); //if it had a function, get the path from target attribute if (get_class($router ->get(0)) == "DOMElement") $r = $router ->get(0) -> getAttribute('target'); else // else get the application with name chain[0] $r = "templates/" . $chain[0] . ".xml"; if (!file_exists($r)) $awsappxmltemplateFile = AWS_ERROR_404; else $awsappxmltemplateFile = $r; $router->topmost()->TEMPLATE_FILE_SOURCE = $awsappxmltemplateFile; if (constant('AWS_USER_ACCESS_DISABLED')) return file_get_contents($awsappxmltemplateFile); else { if ($accessControl -> hasAccess($awsappxmltemplateFile)) return file_get_contents($awsappxmltemplateFile); else return file_get_contents(AWS_ERROR_403); }?><route bind="temp.php"><?aws $el->setAttribute('target','templates/index.xml');?></route><route bind="designer"><?aws $el->setAttribute('target','templates/designer.xml');?></route></router>

 

- ROUTER MODEL 4

- a more advanced router for mod rewrite

- first executes the function of the route element bound to chain[0]

- if the bounded element has an target attribute, after code execution, is using it as a source of application file or, if not found this attribute looks for an application with name templates/.chain[0].xml (where $chain is the path in the SERVER[REQUEST_URI])

- you can call your apps like: http://my-location/appname but also make specific application initialization 

Showing 5 from 0 out of