Development

- Added new Redirect method to SimpleRouter class.
- Changed method-names in InputHandler for better description.
- Fixed return-types for InputHandler for collections.
- Added unit-tests for InputHandler (get, post).
- Optimisations.
This commit is contained in:
Simon Sessingø
2018-04-06 17:20:00 +02:00
parent 30a2ddeed9
commit d38f81836d
15 changed files with 706 additions and 528 deletions
+94 -65
View File
@@ -10,17 +10,17 @@ class InputHandler
/**
* @var array
*/
public $get = [];
protected $get = [];
/**
* @var array
*/
public $post = [];
protected $post = [];
/**
* @var array
*/
public $file = [];
protected $file = [];
/**
* @var Request
@@ -46,7 +46,7 @@ class InputHandler
{
/* Parse get requests */
if (\count($_GET) !== 0) {
$this->get = $this->handleGetPost($_GET);
$this->get = $this->parseInputItem($_GET);
}
/* Parse post requests */
@@ -57,7 +57,7 @@ class InputHandler
}
if (\count($postVars) !== 0) {
$this->post = $this->handleGetPost($postVars);
$this->post = $this->parseInputItem($postVars);
}
/* Parse get requests */
@@ -87,7 +87,7 @@ class InputHandler
}
$keys = [$key];
$files = $this->rearrangeFiles($value['name'], $keys, $value);
$files = $this->rearrangeFile($value['name'], $keys, $value);
if (isset($list[$key]) === true) {
$list[$key][] = $files;
@@ -100,9 +100,16 @@ class InputHandler
return $list;
}
protected function rearrangeFiles(array $values, &$index, $original): array
/**
* Rearrange multi-dimensional file object created by PHP.
*
* @param array $values
* @param array $index
* @param array|null $original
* @return array
*/
protected function rearrangeFile(array $values, &$index, $original): array
{
$originalIndex = $index[0];
array_shift($index);
@@ -138,7 +145,7 @@ class InputHandler
$index[] = $key;
$files = $this->rearrangeFiles($value, $index, $original);
$files = $this->rearrangeFile($value, $index, $original);
if (isset($output[$key]) === true) {
$output[$key][] = $files;
@@ -151,7 +158,13 @@ class InputHandler
return $output;
}
protected function handleGetPost(array $array): array
/**
* Parse input item from array
*
* @param array $array
* @return array
*/
protected function parseInputItem(array $array): array
{
$list = [];
@@ -163,7 +176,7 @@ class InputHandler
continue;
}
$output = $this->handleGetPost($value);
$output = $this->parseInputItem($value);
$list[$key] = $output;
}
@@ -172,62 +185,26 @@ class InputHandler
}
/**
* Find post-value by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @return InputItem|string
*/
public function findPost(string $index, ?string $defaultValue = null)
{
return $this->post[$index] ?? $defaultValue;
}
/**
* Find file by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @return InputFile|string
*/
public function findFile(string $index, ?string $defaultValue = null)
{
return $this->file[$index] ?? $defaultValue;
}
/**
* Find parameter/query-string by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @return InputItem|string
*/
public function findGet(string $index, ?string $defaultValue = null)
{
return $this->get[$index] ?? $defaultValue;
}
/**
* Get input object
* Find input object
*
* @param string $index
* @param array ...$methods
* @return IInputItem|null
* @return IInputItem|array|null
*/
public function get(string $index, ...$methods): ?IInputItem
public function find(string $index, ...$methods)
{
$element = null;
if (\count($methods) === 0 || \in_array('get', $methods, true) === true) {
$element = $this->findGet($index);
$element = $this->get($index);
}
if (($element === null && \count($methods) === 0) || (\count($methods) !== 0 && \in_array('post', $methods, true) === true)) {
$element = $this->findPost($index);
$element = $this->post($index);
}
if (($element === null && \count($methods) === 0) || (\count($methods) !== 0 && \in_array('file', $methods, true) === true)) {
$element = $this->findFile($index);
$element = $this->file($index);
}
return $element;
@@ -239,11 +216,24 @@ class InputHandler
* @param string $index
* @param string|null $defaultValue
* @param array ...$methods
* @return string
* @return string|array
*/
public function getValue(string $index, ?string $defaultValue = null, ...$methods): ?string
public function value(string $index, ?string $defaultValue = null, ...$methods)
{
$input = $this->get($index, ...$methods);
$input = $this->find($index, ...$methods);
$output = [];
/* Handle collection */
if (\is_array($input) === true) {
/* @var $item InputItem */
foreach ($input as $item) {
$output[] = $item->getValue();
}
return (\count($output) === 0) ? $defaultValue : $output;
}
return ($input === null || ($input !== null && trim($input->getValue()) === '')) ? $defaultValue : $input->getValue();
}
@@ -256,15 +246,51 @@ class InputHandler
*/
public function exists(string $index, ...$methods): bool
{
return $this->get($index, ...$methods) !== null;
return $this->value($index, null, ...$methods) !== null;
}
/**
* Find post-value by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @return InputItem|array|string|null
*/
public function post(string $index, ?string $defaultValue = null)
{
return $this->post[$index] ?? $defaultValue;
}
/**
* Find file by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @return InputFile|array|string|null
*/
public function file(string $index, ?string $defaultValue = null)
{
return $this->file[$index] ?? $defaultValue;
}
/**
* Find parameter/query-string by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @return InputItem|array|string|null
*/
public function get(string $index, ?string $defaultValue = null)
{
return $this->get[$index] ?? $defaultValue;
}
/**
* Get all get/post items
* @param array|null $filter Only take items in filter
* @param array $filter Only take items in filter
* @return array
*/
public function all(array $filter = null): array
public function all(array $filter): array
{
$output = $_GET;
@@ -273,13 +299,16 @@ class InputHandler
// Append POST data
$output += $_POST;
$contents = file_get_contents('php://input');
if (\in_array($this->request->getMethod(), ['put', 'patch', 'delete'], false) === true) {
// Append any PHP-input json
if (strpos(trim($contents), '{') === 0) {
$post = json_decode($contents, true);
if ($post !== false) {
$output += $post;
$contents = file_get_contents('php://input');
// Append any PHP-input json
if (strpos(trim($contents), '{') === 0) {
$post = json_decode($contents, true);
if ($post !== false) {
$output += $post;
}
}
}
}
@@ -67,7 +67,7 @@ class BaseCsrfVerifier implements IMiddleware
if ($this->skip($request) === false && \in_array($request->getMethod(), ['post', 'put', 'delete'], true) === true) {
$token = $request->getInputHandler()->getValue(
$token = $request->getInputHandler()->value(
static::POST_KEY,
$request->getHeader(static::HEADER_KEY),
'post'
+2 -2
View File
@@ -86,7 +86,7 @@ class Request
$this->setUrl(new Url($this->getHeader('unencoded-url', $this->getHeader('request-uri'))));
$this->inputHandler = new InputHandler($this);
$this->method = strtolower($this->inputHandler->getValue('_method', $this->getHeader('request-method')));
$this->method = strtolower($this->inputHandler->value('_method', $this->getHeader('request-method')));
}
public function isSecure(): bool
@@ -279,7 +279,7 @@ class Request
*/
public function setMethod(string $method): void
{
$this->method = $method;
$this->method = strtolower($method);
}
/**
+19 -4
View File
@@ -14,7 +14,7 @@ class Url implements \JsonSerializable
private $username;
private $password;
private $path;
private $params;
private $params = [];
private $fragment;
/**
@@ -43,9 +43,7 @@ class Url implements \JsonSerializable
$this->fragment = $data['fragment'] ?? null;
if (isset($data['query']) === true) {
$params = [];
parse_str($data['query'], $params);
$this->setParams($params);
$this->setQueryString($data['query']);
}
}
}
@@ -240,6 +238,23 @@ class Url implements \JsonSerializable
return $this;
}
/**
* Set raw query-string parameters as string
*
* @param string $queryString
* @return static
*/
public function setQueryString(string $queryString): self
{
$params = [];
if(parse_str($queryString, $params) !== false) {
return $this->setParams($params);
}
return $this;
}
/**
* Get query-string params as string
*
+5 -11
View File
@@ -120,9 +120,6 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
$url = '//' . $group->getDomains()[0] . $url;
}
/* Contains parameters that aren't recognized and will be appended at the end of the url */
$unknownParams = [];
/* Create the param string - {parameter} */
$param1 = $this->paramModifiers[0] . '%s' . $this->paramModifiers[1];
@@ -142,7 +139,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
$value = array_key_exists($param, $p) ? $p[$param] : $params[$param];
/* If parameter is specifically set to null - use the original-defined value */
if ($value === null && isset($this->originalParameters[$param])) {
if ($value === null && isset($this->originalParameters[$param]) === true) {
$value = $this->originalParameters[$param];
}
}
@@ -151,13 +148,12 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
/* Add parameter to the correct position */
$url = str_ireplace([sprintf($param1, $param), sprintf($param2, $param)], $value, $url);
} else {
$unknownParams[$param] = $value;
/* Parameter aren't recognized and will be appended at the end of the url */
$url .= $value . '/';
}
}
$url = '/' . ltrim($url, '/') . implode('/', $unknownParams);
return rtrim($url, '/') . '/';
return rtrim('/' . ltrim($url, '/'), '/') . '/';
}
/**
@@ -254,9 +250,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
$this->prependUrl($values['prefix']);
}
parent::setSettings($values, $merge);
return $this;
return parent::setSettings($values, $merge);
}
}
+12 -11
View File
@@ -76,7 +76,9 @@ abstract class Route implements IRoute
}
$router->debug('Parsing parameters');
$parameters = $this->getParameters();
$router->debug('Finished parsing parameters');
/* Filter parameters with null-value */
@@ -118,14 +120,17 @@ abstract class Route implements IRoute
protected function parseParameters($route, $url, $parameterRegex = null)
{
$regex = sprintf(static::PARAMETERS_REGEX_FORMAT, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
$parameters = [];
$regex = null;
if (strpos($route, $this->paramModifiers[0]) !== false) {
$regex = sprintf(static::PARAMETERS_REGEX_FORMAT, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
}
// Ensures that host names/domains will work with parameters
$url = '/' . ltrim($url, '/');
$urlRegex = null;
$parameters = [];
if ((bool)preg_match_all('/' . $regex . '/u', $route, $parameters) === false) {
if ($regex === null || (bool)preg_match_all('/' . $regex . '/u', $route, $parameters) === false) {
$urlRegex = preg_quote($route, '/');
} else {
@@ -155,14 +160,11 @@ abstract class Route implements IRoute
$regex = sprintf('(?:\/|\-)%1$s(?P<%2$s>%3$s)%1$s', $parameters[2][$key], $name, $regex);
}
$urlParts[$key] = preg_quote($t, '/') . $regex;
$urlRegex .= preg_quote($t, '/') . $regex;
}
$urlRegex = implode('', $urlParts);
}
if ((bool)preg_match(sprintf($this->urlRegex, $urlRegex), $url, $matches) === false) {
if ($urlRegex === null || (bool)preg_match(sprintf($this->urlRegex, $urlRegex), $url, $matches) === false) {
return null;
}
@@ -247,9 +249,8 @@ abstract class Route implements IRoute
$this->group = $group;
/* Add/merge parent settings with child */
$this->setSettings($group->toArray(), true);
return $this;
return $this->setSettings($group->toArray(), true);
}
/**
@@ -95,7 +95,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
/* Match global regular-expression for route */
$regexMatch = $this->matchRegex($request, $url);
if ($regexMatch === false || (stripos($url, $this->url) !== 0 && strtolower($url) !== strtolower($this->url))) {
if ($regexMatch === false || (stripos($url, $this->url) !== 0 && strtoupper($url) !== strtoupper($this->url))) {
return false;
}
@@ -177,9 +177,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
$this->names = $values['names'];
}
parent::setSettings($values, $merge);
return $this;
return parent::setSettings($values, $merge);
}
}
+1 -3
View File
@@ -173,9 +173,7 @@ class RouteGroup extends Route implements IGroupRoute
$this->name = $name;
}
parent::setSettings($values, $merge);
return $this;
return parent::setSettings($values, $merge);
}
/**
@@ -92,7 +92,7 @@ class RouteResource extends LoadableRoute implements IControllerRoute
/* Match global regular-expression for route */
$regexMatch = $this->matchRegex($request, $url);
if ($regexMatch === false || (stripos($url, $this->url) !== 0 && strtolower($url) !== strtolower($this->url))) {
if ($regexMatch === false || (stripos($url, $this->url) !== 0 && strtoupper($url) !== strtoupper($this->url))) {
return false;
}
@@ -224,9 +224,7 @@ class RouteResource extends LoadableRoute implements IControllerRoute
$this->methodNames = $values['methods'];
}
parent::setSettings($values, $merge);
return $this;
return parent::setSettings($values, $merge);
}
}
+4 -14
View File
@@ -506,7 +506,6 @@ class Router
}
try {
$this->debug('Start rendering exception handler');
$handler->handleError($this->request, $e);
$this->debug('Finished rendering exception-handler');
@@ -565,7 +564,7 @@ class Router
}
/* Direct match to controller */
if ($route instanceof IControllerRoute && strtolower($route->getController()) === strtolower($name)) {
if ($route instanceof IControllerRoute && strtoupper($route->getController()) === strtoupper($name)) {
$this->debug('Found route "%s" by controller "%s"', $route->getUrl(), $name);
return $route;
@@ -805,26 +804,20 @@ class Router
* Set csrf verifier class
*
* @param BaseCsrfVerifier $csrfVerifier
* @return static
*/
public function setCsrfVerifier(BaseCsrfVerifier $csrfVerifier): self
public function setCsrfVerifier(BaseCsrfVerifier $csrfVerifier): void
{
$this->csrfVerifier = $csrfVerifier;
return $this;
}
/**
* Set class loader
*
* @param IClassLoader $loader
* @return static
*/
public function setClassLoader(IClassLoader $loader)
public function setClassLoader(IClassLoader $loader): void
{
$this->classLoader = $loader;
return $this;
}
/**
@@ -841,13 +834,10 @@ class Router
* Register event handler
*
* @param IEventHandler $handler
* @return static
*/
public function addEventHandler(IEventHandler $handler): self
public function addEventHandler(IEventHandler $handler): void
{
$this->eventHandlers[] = $handler;
return $this;
}
/**
+25 -17
View File
@@ -24,6 +24,7 @@ use Pecee\SimpleRouter\Handlers\IEventHandler;
use Pecee\SimpleRouter\Route\IGroupRoute;
use Pecee\SimpleRouter\Route\IPartialGroupRoute;
use Pecee\SimpleRouter\Route\IRoute;
use Pecee\SimpleRouter\Route\Route;
use Pecee\SimpleRouter\Route\RouteController;
use Pecee\SimpleRouter\Route\RouteGroup;
use Pecee\SimpleRouter\Route\RoutePartialGroup;
@@ -160,6 +161,21 @@ class SimpleRouter
static::router()->addBootManager($bootManager);
}
/**
* Redirect to when route matches.
*
* @param string $where
* @param string $to
* @param int $httpCode
* @return IRoute
*/
public static function redirect($where, $to, $httpCode = 301): IRoute
{
return static::get($where, function () use ($to, $httpCode) {
static::response()->redirect($to, $httpCode);
});
}
/**
* Route the given url to your callback on GET request method.
*
@@ -171,7 +187,7 @@ class SimpleRouter
*/
public static function get(string $url, $callback, array $settings = null): IRoute
{
return static::match(['get'], $url, $callback, $settings);
return static::match([Route::REQUEST_TYPE_GET], $url, $callback, $settings);
}
/**
@@ -184,7 +200,7 @@ class SimpleRouter
*/
public static function post(string $url, $callback, array $settings = null): IRoute
{
return static::match(['post'], $url, $callback, $settings);
return static::match([Route::REQUEST_TYPE_POST], $url, $callback, $settings);
}
/**
@@ -197,7 +213,7 @@ class SimpleRouter
*/
public static function put(string $url, $callback, array $settings = null): IRoute
{
return static::match(['put'], $url, $callback, $settings);
return static::match([Route::REQUEST_TYPE_PUT], $url, $callback, $settings);
}
/**
@@ -210,7 +226,7 @@ class SimpleRouter
*/
public static function patch(string $url, $callback, array $settings = null): IRoute
{
return static::match(['patch'], $url, $callback, $settings);
return static::match([Route::REQUEST_TYPE_PATCH], $url, $callback, $settings);
}
/**
@@ -223,7 +239,7 @@ class SimpleRouter
*/
public static function options(string $url, $callback, array $settings = null): IRoute
{
return static::match(['options'], $url, $callback, $settings);
return static::match([Route::REQUEST_TYPE_OPTIONS], $url, $callback, $settings);
}
/**
@@ -337,9 +353,7 @@ class SimpleRouter
$route->setSettings($settings);
}
static::router()->addRoute($route);
return $route;
return static::router()->addRoute($route);
}
/**
@@ -359,9 +373,7 @@ class SimpleRouter
$route->setSettings($settings);
}
static::router()->addRoute($route);
return $route;
return static::router()->addRoute($route);
}
/**
@@ -381,9 +393,7 @@ class SimpleRouter
$route->setSettings($settings);
}
static::router()->addRoute($route);
return $route;
return static::router()->addRoute($route);
}
/**
@@ -403,9 +413,7 @@ class SimpleRouter
$route->setSettings($settings);
}
static::router()->addRoute($route);
return $route;
return static::router()->addRoute($route);
}
/**