Add Route classes
Route is now replaced with several classes descending from BaseRoute. Each of these routes takes care of autoloading and instantiated the RouteTargetInterface instead of leaving that to the Router.
This commit is contained in:
parent
086dd62f05
commit
618058850d
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace pjdietz\WellRESTed\Interfaces;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a mechanism for obtaining a response given a request.
|
||||||
|
* @package pjdietz\WellRESTed\Interfaces
|
||||||
|
*/
|
||||||
|
interface DispatcherInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param RoutableInterface $request The request to build a responce for.
|
||||||
|
* @return ResponseInterface|null
|
||||||
|
*/
|
||||||
|
public function getResponse(RoutableInterface $request);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pjdietz\WellRESTed\Interfaces\RouteInterface
|
|
||||||
*
|
|
||||||
* @author PJ Dietz <pj@pjdietz.com>
|
|
||||||
* @copyright Copyright 2013 by PJ Dietz
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace pjdietz\WellRESTed\Interfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for a route to relate a pattern for matching a URI to a handler class.
|
|
||||||
* @package pjdietz\WellRESTed
|
|
||||||
*/
|
|
||||||
interface RouteInterface
|
|
||||||
{
|
|
||||||
/** @return string Regex pattern used to match the URI */
|
|
||||||
public function getPattern();
|
|
||||||
|
|
||||||
/** @para string $pattern Regex pattern used to match the URI */
|
|
||||||
public function setPattern($pattern);
|
|
||||||
|
|
||||||
/** @return string Fully qualified name of the class the route will dispatch. */
|
|
||||||
public function getTarget();
|
|
||||||
|
|
||||||
/** @param string $className Fully qualified name of the class the route will dispatch. */
|
|
||||||
public function setTarget($className);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace pjdietz\WellRESTed\Routes;
|
||||||
|
|
||||||
|
use pjdietz\WellRESTed\Interfaces\DispatcherInterface;
|
||||||
|
use pjdietz\WellRESTed\Interfaces\RoutableInterface;
|
||||||
|
use pjdietz\WellRESTed\Interfaces\RouteTargetInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for Routes.
|
||||||
|
* @package pjdietz\WellRESTed\Routes
|
||||||
|
*/
|
||||||
|
abstract class BaseRoute implements DispatcherInterface
|
||||||
|
{
|
||||||
|
/** @var string Fully qualified name for the interface for handlers */
|
||||||
|
const ROUTE_TARGET_INTERFACE = '\\pjdietz\\WellRESTed\\Interfaces\\RouteTargetInterface';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $targetClassName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $targetClassName Fully qualified name to an autoloadable handler class.
|
||||||
|
*/
|
||||||
|
public function __construct($targetClassName)
|
||||||
|
{
|
||||||
|
$this->targetClassName = $targetClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTarget(RoutableInterface $routable)
|
||||||
|
{
|
||||||
|
if (is_subclass_of($this->targetClassName, self::ROUTE_TARGET_INTERFACE)) {
|
||||||
|
/** @var RouteTargetInterface $target */
|
||||||
|
$target = new $this->targetClassName();
|
||||||
|
$target->setRequest($routable);
|
||||||
|
return $target;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace pjdietz\WellRESTed\Routes;
|
||||||
|
|
||||||
|
use pjdietz\WellRESTed\Interfaces\RoutableInterface;
|
||||||
|
|
||||||
|
class RegexRoute extends BaseRoute
|
||||||
|
{
|
||||||
|
private $pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $pattern Regular expression the path must match.
|
||||||
|
* @param string $targetClassName Fully qualified name to an autoloadable handler class.
|
||||||
|
*/
|
||||||
|
public function __construct($pattern, $targetClassName)
|
||||||
|
{
|
||||||
|
parent::__construct($targetClassName);
|
||||||
|
$this->pattern = $pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
/* DispatcherInterface */
|
||||||
|
|
||||||
|
public function getResponse(RoutableInterface $request)
|
||||||
|
{
|
||||||
|
if (preg_match($this->getPattern(), $request->getPath(), $matches)) {
|
||||||
|
$target = $this->getTarget($request);
|
||||||
|
if ($target) {
|
||||||
|
$target->setArguments($matches);
|
||||||
|
return $target->getResponse($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
protected function getPattern()
|
||||||
|
{
|
||||||
|
return $this->pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace pjdietz\WellRESTed\Routes;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use pjdietz\WellRESTed\Interfaces\RoutableInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class StaticRoute
|
||||||
|
* @package pjdietz\WellRESTed\Routes
|
||||||
|
*/
|
||||||
|
class StaticRoute extends BaseRoute
|
||||||
|
{
|
||||||
|
private $paths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|array $paths Path or list of paths the request must match
|
||||||
|
* @param string $targetClassName Fully qualified name to an autoloadable handler class.
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function __construct($paths, $targetClassName)
|
||||||
|
{
|
||||||
|
parent::__construct($targetClassName);
|
||||||
|
if (is_string($paths)) {
|
||||||
|
$this->paths = array($paths);
|
||||||
|
} elseif (is_array($paths)) {
|
||||||
|
$this->paths = $paths;
|
||||||
|
} else {
|
||||||
|
throw new InvalidArgumentException("$paths must be a string or array of string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
/* DispatcherInterface */
|
||||||
|
|
||||||
|
public function getResponse(RoutableInterface $request)
|
||||||
|
{
|
||||||
|
$requestPath = $request->getPath();
|
||||||
|
foreach ($this->paths as $path) {
|
||||||
|
if ($path === $requestPath) {
|
||||||
|
$target = $this->getTarget($request);
|
||||||
|
if ($target) {
|
||||||
|
return $target->getResponse($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace pjdietz\WellRESTed\Routes;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
class TemplateRoute extends RegexRoute
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Regular expression matching URL friendly characters (i.e., letters,
|
||||||
|
* digits, hyphen and underscore)
|
||||||
|
*/
|
||||||
|
const RE_SLUG = '[0-9a-zA-Z\-_]+';
|
||||||
|
/** Regular expression matching digitis */
|
||||||
|
const RE_NUM = '[0-9]+';
|
||||||
|
/** Regular expression matching letters */
|
||||||
|
const RE_ALPHA = '[a-zA-Z]+';
|
||||||
|
/** Regular expression matching letters and digits */
|
||||||
|
const RE_ALPHANUM = '[0-9a-zA-Z]+';
|
||||||
|
/** Regular expression matching a URI template variable (e.g., {id}) */
|
||||||
|
const URI_TEMPLATE_EXPRESSION_RE = '/{([a-zA-Z]+)}/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default regular expression used to match template variable
|
||||||
|
*
|
||||||
|
* @property string
|
||||||
|
*/
|
||||||
|
static public $defaultVariablePattern = self::RE_SLUG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $template URI template the path must match
|
||||||
|
* @param string $targetClassName Fully qualified name to an autoloadable handler class.
|
||||||
|
* @param array|null $variables Associative array of variables from the template and regular expressions.
|
||||||
|
*/
|
||||||
|
public function __construct($template, $targetClassName, $variables = null)
|
||||||
|
{
|
||||||
|
$pattern = $this->buildPattern($template, $variables);
|
||||||
|
parent::__construct($pattern, $targetClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPattern($template, $variables)
|
||||||
|
{
|
||||||
|
if (is_null($variables)) {
|
||||||
|
$variables = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pattern = '';
|
||||||
|
|
||||||
|
// Explode the template into an array of path segments.
|
||||||
|
if ($template[0] === '/') {
|
||||||
|
$parts = explode('/', substr($template, 1));
|
||||||
|
} else {
|
||||||
|
$parts = explode('/', $template);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
|
||||||
|
$pattern .= '\/';
|
||||||
|
|
||||||
|
// Is this part an expression or a literal?
|
||||||
|
if (preg_match(self::URI_TEMPLATE_EXPRESSION_RE, $part, $matches)) {
|
||||||
|
|
||||||
|
// This part of the path is an expresion.
|
||||||
|
|
||||||
|
if (count($matches) === 2) {
|
||||||
|
|
||||||
|
// Locate the name for the variable from the template.
|
||||||
|
$variableName = $matches[1];
|
||||||
|
|
||||||
|
// If the caller passed an array with this variable name
|
||||||
|
// as a key, use its value for the pattern here.
|
||||||
|
// Otherwise, use the class's current default.
|
||||||
|
if (isset($variables[$variableName])) {
|
||||||
|
$variablePattern = $variables[$variableName];
|
||||||
|
} else {
|
||||||
|
$variablePattern = self::$defaultVariablePattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pattern .= sprintf(
|
||||||
|
'(?<%s>%s)',
|
||||||
|
$variableName,
|
||||||
|
$variablePattern
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new InvalidArgumentException('Invalid URI Template.');
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// This part is a literal.
|
||||||
|
$pattern .= $part;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$pattern = '/^' . $pattern . '$/';
|
||||||
|
return $pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue