Skip to content

Commit

Permalink
new hotness -- link generating via better routers
Browse files Browse the repository at this point in the history
  • Loading branch information
henderjon committed Jul 11, 2016
1 parent bee5759 commit d96d057
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 124 deletions.
6 changes: 3 additions & 3 deletions src/Dispatcher/Dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ public function dispatch( RouteInterface $route ){
$fqnsc .= trim($route->getController(), "\\");

if(!class_exists($fqnsc)){
throw new \DomainException("Class not found: {$fqnsc}; via {$route}", 500);
throw new \DomainException("Class not found: {$fqnsc}; via {$route->getController()}", 500);
}

$instance = new \ReflectionClass($fqnsc);

if(!$instance->implementsInterface(DispatchableInterface::class)){
throw new \DomainException("Class missing interface: {$fqnsc}; via {$route}", 500);
throw new \DomainException("Class missing interface: {$fqnsc}; via {$route->getAction()}", 500);
}

$shouldInit = false;
Expand All @@ -78,7 +78,7 @@ public function dispatch( RouteInterface $route ){

if($method){
if(!method_exists($obj, $method)){
throw new \InvalidArgumentException("Method '{$method}' not found on ".get_class($obj)."; via {$route}", 404);
throw new \InvalidArgumentException("Method '{$method}' not found on ".get_class($obj), 404);
}
$obj = [$obj, $method];
}
Expand Down
78 changes: 64 additions & 14 deletions src/Router/AbstractRouter.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

namespace Chevron\Kernel\Router;

/**
* A very simple and quite opinionated routing system, this is here ONLY to tweak
* inheritence later on if I get the urge.
Expand All @@ -10,28 +11,34 @@
*/
abstract class AbstractRouter {

/**
* the default action
*/
protected $default_action = "index";
const DEFAULT_ACTION = "index";
const DEFAULT_FORMAT = "html";

/**
* set the default action
* @var The root namespace to which requests are routed
*/
public function setDefaultAction($action){
$this->default_action = $action;
protected $rootNamespace;

public function __construct($ns = "\\"){
$this->rootNamespace = $this->trimSlashes($ns);
}

/**
* the default format
* trim the slashes from a string
* @param string $name The string
* @return string
*/
protected $default_format = "html";
protected function trimSlashes($name){
return trim($name, " /\\");
}

/**
* set the default format
* check if a class is in the root namespace
* @param string $class The fully qualified class name
* @return bool
*/
public function setDefaultFormat($format){
$this->default_format = $format;
protected function isOfNamespace($class){
return stripos($this->trimSlashes($class), $this->rootNamespace . "\\") === 0;
}

/**
Expand Down Expand Up @@ -63,8 +70,8 @@ protected function parseRequest($path){
$controller = $class;
}

$method = $this->default_action;
$format = $this->default_format;
$method = self::DEFAULT_ACTION;
$format = self::DEFAULT_FORMAT;
if($action){
$method = $action;
if(($pos = strpos($action, ".")) !== false){
Expand All @@ -81,4 +88,47 @@ protected function parseRequest($path){
return [$controller, $method, $format, $query];
}

/**
* @inheritdoc
*/
public function generate($controller, $action = null, $format = null, array $options = []){
return $this->generateFromRoute(new Route($controller, $action, $format, $options));
}

/**
* reverse a Route into it's url
* @param Route $route
* @return string
*/
protected function generateFromRoute(Interfaces\RouteInterface $route){

$controller = $route->getController();


if(is_object($controller)){
drop($route);
}

if($this->isOfNamespace($controller)){
$controller = substr($controller, strlen($this->rootNamespace));
}

$prefix = strtolower(strtr(trim($controller, DIRECTORY_SEPARATOR), "\\", "/"));

$action = strtolower($route->getAction() ?: self::DEFAULT_ACTION);

$format = strtolower($route->getFormat() ?: self::DEFAULT_FORMAT);

$query = "";
if($route->getParams()){
$query = http_build_query($route->getParams());
}

return rtrim(sprintf("%s/%s.%s?%s", $prefix, $action, $format, $query), " ?./");
}

}




6 changes: 0 additions & 6 deletions src/Router/Interfaces/RouteInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,4 @@ public function getFormat();
*/
public function getParams();

/**
* output the string version of the route
* @return string
*/
public function __toString();

}
10 changes: 10 additions & 0 deletions src/Router/Interfaces/RouterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,14 @@ interface RouterInterface {
*/
public function match($path);

/**
* create a link from the raw components of a route
* @param string $controller The dispatchable class
* @param string $action The method of the class
* @param string $format The format of the resonse
* @param array $options The key => val to use in the query string
* @return string
*/
public function generate($controller, $action = null, $format = null, array $options = []);

}
95 changes: 24 additions & 71 deletions src/Router/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@
class Route implements Interfaces\RouteInterface{

const DEFAULT_CONTROLLER = "index";

const CONTROLLER_KEY = "controller";

const ACTION_KEY = "action";

const FORMAT_KEY = "format";
const PARAMS_KEY = "query";

/**
* the value to return as the requested controller.
Expand Down Expand Up @@ -49,19 +47,9 @@ class Route implements Interfaces\RouteInterface{
*/
public function __construct($controller, $action = null, $format = null, array $params = []){
$this->controller = $controller ?: self::DEFAULT_CONTROLLER;

if($action){
$this->setAction($action);
}

if($format){
$this->setFormat($format);
}

if($params){
$this->setParams($params);
}

$this->setAction($action);
$this->setFormat($format);
$this->setParams($params);
}

/**
Expand Down Expand Up @@ -96,61 +84,6 @@ public function getParams(){
return $this->params;
}

/**
* get a unique 8 char hash of the request
*/
public function getHash(){
return substr(sha1($this->__toString()), 0, 8);
}

/**
* output the route as an array
* @return array
*/
public function toArray(){
return [
static::CONTROLLER_KEY => $this->getController(),
static::ACTION_KEY => $this->getAction(),
static::FORMAT_KEY => $this->getFormat(),
];
}

/**
* create a link looking string from the properties of the route
*/
public function __toString(){

$route = strtolower(strtr(trim($this->getController(), DIRECTORY_SEPARATOR), "\\", "/")) . "/";

if($this->action){
$route .= strtolower($this->getAction());
}

if($this->format){
$route .= "." . strtolower($this->getFormat());
}

if($this->params){
$route .= "?" . http_build_query($this->getParams());
}

return ltrim($route, "/");
}

/**
* add a namespace prefix to the route's link looking string on the off
* chance that you're dispatching from a specific namespace
* @param string $namespace The prefix for the link
*/
public function link($namespace = ""){
$prefix = "";
if($namespace){
$prefix = strtolower(trim($namespace, "\\/"));
}
$link = ltrim($this->__toString(), "/");
return ltrim("{$prefix}/{$link}", "/");
}

/**
* get the action
* @param string $action
Expand Down Expand Up @@ -178,4 +111,24 @@ public function setParams(array $params){
$this->params = $params;
}

/**
* get a unique 8 char hash of the request
*/
public function getHash(){
return substr(sha1(json_encode($this->toArray())), 0, 8);
}

/**
* output the route as an array
* @return array
*/
public function toArray(){
return [
static::CONTROLLER_KEY => $this->getController(),
static::ACTION_KEY => $this->getAction(),
static::FORMAT_KEY => $this->getFormat(),
static::PARAMS_KEY => $this->getParams(),
];
}

}
24 changes: 24 additions & 0 deletions src/Router/RouteFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Chevron\Kernel\Router;
/**
* an object representing a parsed route
*
* @package Chevron\Kernel
* @author Jon Henderson
*/
class RouteFactory {

/**
* create a Route
* @param string $controller the value to return as the requested controller.
* @param string $action the action method to call on the controller object, once instantiated
* @param string $format the format the response should take
* @param array array $params an array of the parsed query string
* @return \Chevron\Router\Route
*/
public function make($controller, $action = null, $format = null, array $params = []){
return new Route($controller, $action, $format, $params);
}

}
16 changes: 16 additions & 0 deletions tests/PHPUnit/Router/BasicRouterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,20 @@ function test_parsePath(){

}

function test_generate(){

$router = new Router\BasicRouter("\\Name\\Space");

$expected = "/class/method.html";

$result = $router->generate("Name\\Space\\Class",
"method",
"html",
[]
);

$this->assertEquals($expected, $result);

}

}
33 changes: 3 additions & 30 deletions tests/PHPUnit/Router/RouteTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,51 +11,24 @@ function test___construct(){

}

function test___toString_1(){
$obj = new \Chevron\Kernel\Router\Route("\\Namespace\\Controller", "action", null, ["query" => "param"]);
$result = (string)$obj;
$expected = "namespace/controller/action?query=param";
$this->assertEquals($expected, $result);
}

function test_toArray(){
$obj = new \Chevron\Kernel\Router\Route("\\Namespace\\Controller", "action", null, ["query" => "param"]);
$result = $obj->toArray();
$expected = [
\Chevron\Kernel\Router\Route::CONTROLLER_KEY => "\\Namespace\\Controller",
\Chevron\Kernel\Router\Route::ACTION_KEY => "action",
\Chevron\Kernel\Router\Route::FORMAT_KEY => null,
\Chevron\Kernel\Router\Route::PARAMS_KEY => ["query" => "param"],
];
$this->assertEquals($expected, $result);
}

function test___toString_2(){
$obj = new \Chevron\Kernel\Router\Route("\\Namespace\\Controller", null, "json", []);
$result = (string)$obj;
$expected = "namespace/controller/.json";
$this->assertEquals($expected, $result);
}

function test___toString_3(){
$obj = new \Chevron\Kernel\Router\Route("Namespace\\Controller", null, "json", []);
$result = (string)$obj;
$expected = "namespace/controller/.json";
$this->assertEquals($expected, $result);
}

function test_linkify(){
$obj = new \Chevron\Kernel\Router\Route("\\Controller", null, "json", []);
$result = $obj->link("\\Namespace\\");
$expected = "namespace/controller/.json";
$this->assertEquals($expected, $result);
}

function test_getHash(){
$obj = new \Chevron\Kernel\Router\Route("\\Namespace\\Controller", "action", null, ["query" => "param"]);
$result = $obj->getHash();
$expected = "namespace/controller/action?query=param";
$expected = json_encode($obj->toArray());
$expected = substr(sha1($expected), 0, 8);
$this->assertEquals($expected, $result);
}

}
}

0 comments on commit d96d057

Please sign in to comment.