Remove RouteBuilder and ParseException
This commit is contained in:
parent
d95498bcae
commit
f3e5cddf4a
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* pjdietz\WellRESTed\Exceptions\ParseException
|
||||
*
|
||||
* @author PJ Dietz <pj@pjdietz.com>
|
||||
* @copyright Copyright 2015 by PJ Dietz
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace pjdietz\WellRESTed\Exceptions;
|
||||
|
||||
/**
|
||||
* Exception related to a parsing data.
|
||||
*/
|
||||
class ParseException extends WellRESTedException
|
||||
{
|
||||
}
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* pjdietz\WellRESTed\RouteBuilder
|
||||
*
|
||||
* @author PJ Dietz <pj@pjdietz.com>
|
||||
* @copyright Copyright 2015 by PJ Dietz
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
namespace pjdietz\WellRESTed;
|
||||
|
||||
use pjdietz\WellRESTed\Exceptions\ParseException;
|
||||
use pjdietz\WellRESTed\Interfaces\HandlerInterface;
|
||||
use pjdietz\WellRESTed\Routes\RegexRoute;
|
||||
use pjdietz\WellRESTed\Routes\StaticRoute;
|
||||
use pjdietz\WellRESTed\Routes\TemplateRoute;
|
||||
|
||||
/**
|
||||
* Class for facilitating constructing Routers.
|
||||
*
|
||||
* @deprecated Use {@see Router::add} instead.
|
||||
* @see Router::add
|
||||
*/
|
||||
class RouteBuilder
|
||||
{
|
||||
/** @var string Regex pattern to use for URI template patters. */
|
||||
private $defaultVariablePattern;
|
||||
/** @var string Common prefix to affix to handler class names. */
|
||||
private $handlerNamespace;
|
||||
/** @var array Associative array of variable names and regex patterns. */
|
||||
private $templateVariablePatterns;
|
||||
|
||||
/**
|
||||
* Create a new RouteBuilder
|
||||
*
|
||||
* @deprecated Use {@see Router::add} instead.
|
||||
* @see Router::add
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
trigger_error("RouteBuilder is deprecated. Use Router::add", E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contruct and return an array of routes.
|
||||
*
|
||||
* If $data is a string, buildRoutes() will parse it as JSON with json_decode.
|
||||
*
|
||||
* If $data is an array, buildRoutes() assumes each item in the array is
|
||||
* an object it can translate into a route.
|
||||
*
|
||||
* If $data is an object, buildRoutes() assumes it will have a "routes"
|
||||
* property with an array value that is a collection of objects to
|
||||
* translate into routes. Any other properties will be read with
|
||||
* readConfiguration()
|
||||
*
|
||||
* @param string|array|object $data Description of routes to build.
|
||||
* @return array List of routes to add to a router.
|
||||
* @throws Exceptions\ParseException
|
||||
*/
|
||||
public function buildRoutes($data)
|
||||
{
|
||||
// If $data is a string, attempt to parse it as JSON.
|
||||
if (is_string($data)) {
|
||||
$data = json_decode($data);
|
||||
if (is_null($data)) {
|
||||
throw new ParseException("Unable to parse as JSON.");
|
||||
}
|
||||
}
|
||||
|
||||
// Locate the list of routes. This should be one of these:
|
||||
// - If $data is an object, $data->routes
|
||||
// - If $data is an array, $data
|
||||
if (is_array($data)) {
|
||||
$dataRoutes = $data;
|
||||
} elseif (is_object($data) && isset($data->routes) && is_array($data->routes)) {
|
||||
$dataRoutes = $data->routes;
|
||||
$this->readConfiguration($data);
|
||||
} else {
|
||||
throw new ParseException("Unable to parse. Missing array of routes.");
|
||||
}
|
||||
|
||||
// Build a route instance and append it to the list.
|
||||
$routes = array();
|
||||
foreach ($dataRoutes as $item) {
|
||||
$routes[] = $this->buildRoute($item);
|
||||
}
|
||||
return $routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an object and update the instances with the new configuration.
|
||||
*
|
||||
* handlerNamespace is passed to setHandlerNamesapce()
|
||||
|
||||
* variablePattern is passed to setDefaultVariablePattern()
|
||||
*
|
||||
* vars is passed to setTemplateVars()
|
||||
*
|
||||
* @param object
|
||||
*/
|
||||
public function readConfiguration($data)
|
||||
{
|
||||
if (isset($data->handlerNamespace)) {
|
||||
$this->setHandlerNamespace($data->handlerNamespace);
|
||||
}
|
||||
if (isset($data->variablePattern)) {
|
||||
$this->setDefaultVariablePattern($data->variablePattern);
|
||||
}
|
||||
if (isset($data->vars)) {
|
||||
$this->setTemplateVars((array) $data->vars);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string to prepend to handler class names.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHandlerNamespace()
|
||||
{
|
||||
return $this->handlerNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prefix to prepend to handler class names.
|
||||
*
|
||||
* @param mixed $handlerNamespace
|
||||
*/
|
||||
public function setHandlerNamespace($handlerNamespace = "")
|
||||
{
|
||||
$this->handlerNamespace = $handlerNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an associative array of variable names and regex patterns.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTemplateVars()
|
||||
{
|
||||
return $this->templateVariablePatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the array of template variable patterns.
|
||||
*
|
||||
* Keys are names of variables for use in URI template (do not include {}).
|
||||
* Values are regex patterns or any of the following special names: SLUG,
|
||||
* ALPHA, ALPHANUM, DIGIT, NUM.
|
||||
*
|
||||
* If you wish to use additional named patterns, subclass RouteBuilder and
|
||||
* override getTemplateVariablePattern.
|
||||
*
|
||||
* @param array $vars Associative array of variable name => pattern
|
||||
*/
|
||||
public function setTemplateVars(array $vars)
|
||||
{
|
||||
foreach ($vars as $name => $var) {
|
||||
$vars[$name] = $this->getTemplateVariablePattern($var);
|
||||
}
|
||||
$this->templateVariablePatterns = $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default regex pattern to use for URI template variables.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultVariablePattern()
|
||||
{
|
||||
return $this->defaultVariablePattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default regex pattern to use for URI template variables.
|
||||
*
|
||||
* $defaultVariablePattern may be a regex pattern or one of the following:
|
||||
* SLUG, ALPHA, ALPHANUM, DIGIT, NUM.
|
||||
*
|
||||
* If you wish to use additional named patterns, subclass RouteBuilder and
|
||||
* override getTemplateVariablePattern.
|
||||
*
|
||||
* @param mixed $defaultVariablePattern
|
||||
*/
|
||||
public function setDefaultVariablePattern($defaultVariablePattern)
|
||||
{
|
||||
$this->defaultVariablePattern = $this->getTemplateVariablePattern($defaultVariablePattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return an appropriate route given an object describing a route.
|
||||
*
|
||||
* $item must contain a "handler" property providing the classname for the
|
||||
* HandlerInterface to call getResponse() on if the route matches. "handler"
|
||||
* may be fully qualified and begin with "\". If it does not begin with "\",
|
||||
* the instance's $handlerNamespace is affixed to the begining.
|
||||
*
|
||||
* $item must also contain a "path", "template", or "pattern" property to
|
||||
* indicate how to create the StaticRoute, TemplateRoute, or RegexRoute.
|
||||
*
|
||||
* @param object|array $item
|
||||
* @return HandlerInterface
|
||||
* @throws Exceptions\ParseException
|
||||
*/
|
||||
protected function buildRoute($item)
|
||||
{
|
||||
// Determine the handler for this route.
|
||||
if (isset($item->handler)) {
|
||||
$handler = $item->handler;
|
||||
if ($handler[0] != "\\") {
|
||||
$handler = $this->getHandlerNamespace() . "\\" . $handler;
|
||||
}
|
||||
} else {
|
||||
throw new ParseException("Unable to parse. Route is missing a handler.");
|
||||
}
|
||||
|
||||
// Static Route
|
||||
if (isset($item->path)) {
|
||||
return new StaticRoute($item->path, $handler);
|
||||
}
|
||||
|
||||
// Template Route
|
||||
if (isset($item->template)) {
|
||||
$vars = isset($item->vars) ? (array) $item->vars : array();
|
||||
foreach ($vars as $name => $var) {
|
||||
$vars[$name] = $this->getTemplateVariablePattern($var);
|
||||
}
|
||||
if ($this->templateVariablePatterns) {
|
||||
$vars = array_merge($this->templateVariablePatterns, $vars);
|
||||
}
|
||||
return new TemplateRoute($item->template, $handler, $this->getDefaultVariablePattern(), $vars);
|
||||
}
|
||||
|
||||
// Regex Route
|
||||
if (isset($item->pattern)) {
|
||||
return new RegexRoute($item->pattern, $handler);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a regular expression pattern given a name.
|
||||
*
|
||||
* The names SLUG, ALPHA, ALPHANUM, DIGIT, NUM convert to regex patterns.
|
||||
* Anything else passes through as is.
|
||||
*
|
||||
* If you wish to use additional named patterns, subclass RouteBuilder and
|
||||
* override getTemplateVariablePattern.
|
||||
*
|
||||
* @param string $variable Regex pattern or name (SLUG, ALPHA, ALPHANUM, DIGIT, NUM
|
||||
* @return string
|
||||
*/
|
||||
protected function getTemplateVariablePattern($variable)
|
||||
{
|
||||
switch ($variable) {
|
||||
case "SLUG":
|
||||
return TemplateRoute::RE_SLUG;
|
||||
case "ALPHA":
|
||||
return TemplateRoute::RE_ALPHA;
|
||||
case "ALPHANUM":
|
||||
return TemplateRoute::RE_ALPHANUM;
|
||||
case "DIGIT":
|
||||
case "NUM":
|
||||
return TemplateRoute::RE_NUM;
|
||||
default:
|
||||
return $variable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,211 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace pjdietz\WellRESTed\Test;
|
||||
|
||||
use pjdietz\WellRESTed\RouteBuilder;
|
||||
use pjdietz\WellRESTed\Routes\TemplateRoute;
|
||||
use stdClass;
|
||||
|
||||
class RouteBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/*
|
||||
* Parse JSON and get the correct number of routes.
|
||||
*/
|
||||
public function testBuildRoutesFromJson()
|
||||
{
|
||||
$json = <<<'JSON'
|
||||
{
|
||||
"handlerNamespace": "\\myapi\\Handlers",
|
||||
"routes": [
|
||||
{
|
||||
"path": "/",
|
||||
"handler": "RootHandler"
|
||||
},
|
||||
{
|
||||
"path": "/cats/",
|
||||
"handler": "CatCollectionHandler"
|
||||
},
|
||||
{
|
||||
"tempalte": "/cats/{id}",
|
||||
"handler": "CatItemHandler"
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON;
|
||||
|
||||
$builder = @new RouteBuilder();
|
||||
$routes = $builder->buildRoutes($json);
|
||||
$this->assertEquals(3, count($routes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fail properly on malformed JSON
|
||||
*
|
||||
* @expectedException \pjdietz\WellRESTed\Exceptions\ParseException
|
||||
* @expectedExceptionMessage Unable to parse as JSON.
|
||||
*/
|
||||
public function testThrowsExceptionBuildingRoutesFromInvalidJson()
|
||||
{
|
||||
$json = "jadhjaksd";
|
||||
$builder = @new RouteBuilder();
|
||||
$builder->buildRoutes($json);
|
||||
}
|
||||
|
||||
public function testSetsNamesapce()
|
||||
{
|
||||
$namespace = "\\test\\Namespace";
|
||||
$builder = @new RouteBuilder();
|
||||
$builder->setHandlerNamespace($namespace);
|
||||
$this->assertEquals($namespace, $builder->getHandlerNamespace());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider varProvider
|
||||
*/
|
||||
public function testSetsDefaultVariablePatternThroughAccessor($name, $pattern, $expected)
|
||||
{
|
||||
$builder = @new RouteBuilder();
|
||||
$builder->setDefaultVariablePattern($pattern);
|
||||
$this->assertEquals($builder->getDefaultVariablePattern(), $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider varProvider
|
||||
*/
|
||||
public function testSetsDefaultVariablePatternThroughConfiguration($name, $pattern, $expected)
|
||||
{
|
||||
$builder = @new RouteBuilder();
|
||||
$conf = new stdClass();
|
||||
$conf->variablePattern = $pattern;
|
||||
$builder->readConfiguration($conf);
|
||||
$this->assertEquals($builder->getDefaultVariablePattern(), $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider varProvider
|
||||
*/
|
||||
public function testSetsTemplateVariablesThroughAccessor($name, $pattern, $expected)
|
||||
{
|
||||
$builder = @new RouteBuilder();
|
||||
$builder->setTemplateVars(array($name => $pattern));
|
||||
$vars = $builder->getTemplateVars();
|
||||
$this->assertEquals($vars[$name], $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider varProvider
|
||||
*/
|
||||
public function testSetsTemplateVariablesThroughConfiguration($name, $pattern, $expected)
|
||||
{
|
||||
$builder = @new RouteBuilder();
|
||||
$conf = new stdClass();
|
||||
$conf->vars = [$name => $pattern];
|
||||
$builder->readConfiguration($conf);
|
||||
$vars = $builder->getTemplateVars();
|
||||
$this->assertEquals($vars[$name], $expected);
|
||||
}
|
||||
|
||||
public function varProvider()
|
||||
{
|
||||
return [
|
||||
["slug", "SLUG", TemplateRoute::RE_SLUG],
|
||||
["name", "ALPHA", TemplateRoute::RE_ALPHA],
|
||||
["name", "ALPHANUM", TemplateRoute::RE_ALPHANUM],
|
||||
["id", "DIGIT", TemplateRoute::RE_NUM],
|
||||
["id", "NUM", TemplateRoute::RE_NUM],
|
||||
["custom", ".*", ".*"]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider routeDescriptionProvider
|
||||
*/
|
||||
public function testBuildsRoutesFromRoutesArray($key, $value, $expectedClass)
|
||||
{
|
||||
$mockHander = $this->getMock('\pjdietz\WellRESTed\Interfaces\HandlerInterface');
|
||||
$routes = [
|
||||
(object) [
|
||||
$key => $value,
|
||||
"handler" => get_class($mockHander)
|
||||
]
|
||||
];
|
||||
$builder = @new RouteBuilder();
|
||||
$routes = $builder->buildRoutes($routes);
|
||||
$route = $routes[0];
|
||||
$this->assertInstanceOf($expectedClass, $route);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider routeDescriptionProvider
|
||||
*/
|
||||
public function testBuildsRoutesFromConfigurationObject($key, $value, $expectedClass)
|
||||
{
|
||||
$mockHander = $this->getMock('\pjdietz\WellRESTed\Interfaces\HandlerInterface');
|
||||
$conf = (object) [
|
||||
"routes" => [
|
||||
(object) [
|
||||
$key => $value,
|
||||
"handler" => get_class($mockHander)
|
||||
]
|
||||
]
|
||||
];
|
||||
$builder = @new RouteBuilder();
|
||||
$routes = $builder->buildRoutes($conf);
|
||||
$route = $routes[0];
|
||||
$this->assertInstanceOf($expectedClass, $route);
|
||||
}
|
||||
|
||||
public function routeDescriptionProvider()
|
||||
{
|
||||
return [
|
||||
["path", "/", '\pjdietz\WellRESTed\Routes\StaticRoute'],
|
||||
["pattern", "/cat/[0-9]+", '\pjdietz\WellRESTed\Routes\RegexRoute'],
|
||||
["template", "/cat/{id}", '\pjdietz\WellRESTed\Routes\TemplateRoute'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testBuildsRoutesWithTemplateVariables()
|
||||
{
|
||||
$mock = $this->getMock('\pjdietz\WellRESTed\Interfaces\HandlerInterface');
|
||||
$routes = [
|
||||
(object) [
|
||||
"template" => "/cats/{catId}",
|
||||
"handler" => get_class($mock),
|
||||
"vars" => [
|
||||
"catId" => "SLUG"
|
||||
]
|
||||
]
|
||||
];
|
||||
$builder = @new RouteBuilder();
|
||||
$builder->setTemplateVars(["dogId" => "NUM"]);
|
||||
$routes = $builder->buildRoutes($routes);
|
||||
$route = $routes[0];
|
||||
$this->assertInstanceOf('\pjdietz\WellRESTed\Routes\TemplateRoute', $route);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \pjdietz\WellRESTed\Exceptions\ParseException
|
||||
* @expectedExceptionMessage Unable to parse. Missing array of routes.
|
||||
*/
|
||||
public function testThrowsExceptionWhenConfigurationObjectIsMissingRoutesArray()
|
||||
{
|
||||
$conf = new stdClass();
|
||||
$builder = @new RouteBuilder();
|
||||
$builder->buildRoutes($conf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \pjdietz\WellRESTed\Exceptions\ParseException
|
||||
* @expectedExceptionMessage Unable to parse. Route is missing a handler.
|
||||
*/
|
||||
public function testThrowsExceptionWhenMissingHandler()
|
||||
{
|
||||
$routes = [
|
||||
(object) [
|
||||
"path" => "/"
|
||||
]
|
||||
];
|
||||
$builder = @new RouteBuilder();
|
||||
$builder->buildRoutes($routes);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue