Compare commits

...

20 Commits

Author SHA1 Message Date
Simon Sessingø b7c31ae434 Merge pull request #553 from skipperbent/v4-development
Version 4.3.4.1
2021-05-19 04:43:29 +02:00
Simon Sessingø 0c329e4c5b Merge pull request #552 from skipperbent/v4-exception-callback-fix
SimpleRouter::error not working within group
2021-05-19 04:42:35 +02:00
Simon Sessingø e057a76153 Removed unused variable. 2021-05-19 04:41:36 +02:00
Simon Sessingø f7f1f1e3de Fixed issue causing SimpleRouter::exception helper not to work when used within a group (issue: #551) 2021-05-19 04:31:50 +02:00
Simon Sessingø f93621fa02 Merge pull request #549 from skipperbent/v4-development
Version 4.3.4.0
2021-05-19 00:45:32 +02:00
Simon Sessingø 5ab8826bfb Merge pull request #548 from skipperbent/v4-inputitem-array
InputHandler optimisations.
2021-05-19 00:42:48 +02:00
Simon Sessingø f863f931d8 Fixed php8 php-unit tests compatibility. 2021-05-18 18:08:41 +02:00
Simon Sessingø 0d6326dfbb InputHandler optimisations.
- InputItem can now be used like array (for example: input()->get('items')[0]) if value is array.
- Changed default-value parameter for get, post, file can now be mixed to allow object as return-type.
2021-05-18 18:00:18 +02:00
Simon Sessingø 448a423d5d Merge pull request #544 from skipperbent/v4-development
Version 4.3.3.0
2021-05-02 14:00:10 +02:00
Simon Sessingø df9a855579 Merge pull request #543 from skipperbent/v4-bugfixes
Bugfixes
2021-05-02 13:58:00 +02:00
Simon Sessingø d6bd9bbd72 Development
- [FEATURE] Namespace overwrite now works globally. 'Service¨' will append namespace whereas '\Service' will overwrite it.
- [FEATURE] Exceptionhandlers are now rendered in reverse order from newest to oldest. This allows for exceptions to be handled from parent exceptions which were otherwise ignored.
- Fixed incorrect return type for InputFile::getError to nullable int.
- Added return type to all, match, controller and resource in SimpleRouter class.
- Fixed incorrect usage of parse_str in Url::setQueryString method.
- Fixed incorrect expected value in array_flip in Url::removeParams method.
2021-05-02 13:48:13 +02:00
Simon Sessingø 569b3a8760 Merge pull request #541 from skipperbent/v4-development
Version 4.3.2.3
2021-04-28 10:05:34 +02:00
Simon Sessingø 79a075ef49 Merge pull request #540 from skipperbent/v4-type-hint-notice
Fixed deprecated notice when using class type hinting (issue: #538)
2021-04-28 10:03:55 +02:00
Simon Sessingø c66d7f7df7 Fixed deprecated notice when using class type hinting (issue: #538) 2021-04-28 09:57:47 +02:00
Simon Sessingø c6d0ff3c0e Merge pull request #536 from skipperbent/v4-development
Version 4.3.2.2
2021-04-28 03:41:47 +02:00
Simon Sessingø 718d60c53b Removed return type from IResourceController as the return type can be mixed. 2021-04-04 11:21:26 +02:00
Simon Sessingø 2a573f27fe Merge pull request #534 from skipperbent/v4-development
Version 4.3.2.1
2021-04-01 03:16:29 +02:00
Simon Sessingø ecbb0825e0 Added include param parameter to Url::getAbsoluteUrl method. 2021-04-01 03:14:22 +02:00
Simon Sessingø b94dc4355f Optimisations 2021-04-01 03:11:05 +02:00
Simon Sessingø 52c6c226c0 [BUGFIX] Fixed issue with BaseCsrfVerifier matching urls against urls with parameters.
- Added optional $includeParams parameter to Url::getRelativeUrl method.
2021-04-01 03:04:32 +02:00
16 changed files with 174 additions and 85 deletions
+14 -14
View File
@@ -6,43 +6,43 @@ interface IResourceController
{
/**
* @return string|null
* @return mixed
*/
public function index(): ?string;
public function index();
/**
* @param mixed $id
* @return string|null
* @return mixed
*/
public function show($id): ?string;
public function show($id);
/**
* @return string|null
* @return mixed
*/
public function store(): ?string;
public function store();
/**
* @return string|null
* @return mixed
*/
public function create(): ?string;
public function create();
/**
* View
* @param mixed $id
* @return string|null
* @return mixed
*/
public function edit($id): ?string;
public function edit($id);
/**
* @param mixed $id
* @return string|null
* @return mixed
*/
public function update($id): ?string;
public function update($id);
/**
* @param mixed $id
* @return string|null
* @return mixed
*/
public function destroy($id): ?string;
public function destroy($id);
}
+9 -9
View File
@@ -165,7 +165,7 @@ class InputFile implements IInputItem
* @param string $name
* @return static
*/
public function setFilename($name): IInputItem
public function setFilename(string $name): IInputItem
{
$this->filename = $name;
@@ -188,7 +188,7 @@ class InputFile implements IInputItem
* @param string $destination
* @return bool
*/
public function move($destination): bool
public function move(string $destination): bool
{
return move_uploaded_file($this->tmpName, $destination);
}
@@ -216,20 +216,20 @@ class InputFile implements IInputItem
/**
* Get upload-error code.
*
* @return int
* @return int|null
*/
public function getError(): int
public function getError(): ?int
{
return (int)$this->errors;
return $this->errors;
}
/**
* Set error
*
* @param int $error
* @param int|null $error
* @return static
*/
public function setError($error): IInputItem
public function setError(?int $error): IInputItem
{
$this->errors = (int)$error;
@@ -249,7 +249,7 @@ class InputFile implements IInputItem
* @param string $name
* @return static
*/
public function setTmpName($name): IInputItem
public function setTmpName(string $name): IInputItem
{
$this->tmpName = $name;
@@ -261,7 +261,7 @@ class InputFile implements IInputItem
return $this->getTmpName();
}
public function getValue()
public function getValue(): string
{
return $this->getFilename();
}
+7 -7
View File
@@ -147,7 +147,7 @@ class InputHandler
* @param array|null $original
* @return array
*/
protected function rearrangeFile(array $values, &$index, $original): array
protected function rearrangeFile(array $values, array &$index, ?array $original): array
{
$originalIndex = $index[0];
array_shift($index);
@@ -308,10 +308,10 @@ class InputHandler
* Find post-value by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @param mixed|null $defaultValue
* @return InputItem|array|string|null
*/
public function post(string $index, ?string $defaultValue = null)
public function post(string $index, $defaultValue = null)
{
return $this->post[$index] ?? $defaultValue;
}
@@ -320,10 +320,10 @@ class InputHandler
* Find file by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @param mixed|null $defaultValue
* @return InputFile|array|string|null
*/
public function file(string $index, ?string $defaultValue = null)
public function file(string $index, $defaultValue = null)
{
return $this->file[$index] ?? $defaultValue;
}
@@ -332,10 +332,10 @@ class InputHandler
* Find parameter/query-string by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @param mixed|null $defaultValue
* @return InputItem|array|string|null
*/
public function get(string $index, ?string $defaultValue = null)
public function get(string $index, $defaultValue = null)
{
return $this->get[$index] ?? $defaultValue;
}
+27 -1
View File
@@ -2,10 +2,11 @@
namespace Pecee\Http\Input;
use ArrayAccess;
use ArrayIterator;
use IteratorAggregate;
class InputItem implements IInputItem, IteratorAggregate
class InputItem implements ArrayAccess, IInputItem, IteratorAggregate
{
public $index;
public $name;
@@ -75,9 +76,34 @@ class InputItem implements IInputItem, IteratorAggregate
return $this;
}
public function offsetExists($offset): bool
{
return isset($this->value[$offset]);
}
public function offsetGet($offset)
{
if ($this->offsetExists($offset) === true) {
return $this->value[$offset];
}
return null;
}
public function offsetSet($offset, $value): void
{
$this->value[$offset] = $value;
}
public function offsetUnset($offset): void
{
unset($this->data[$offset]);
}
public function __toString(): string
{
$value = $this->getValue();
return (is_array($value) === true) ? json_encode($value) : $value;
}
@@ -50,12 +50,12 @@ class BaseCsrfVerifier implements IMiddleware
$url = rtrim($url, '*');
$skip = $request->getUrl()->contains($url);
} else {
$skip = ($url === $request->getUrl()->getOriginalUrl());
$skip = ($url === rtrim($request->getUrl()->getRelativeUrl(false), '/'));
}
if ($skip === true) {
if($this->include !== null && count($this->include) > 0) {
if(is_array($this->include) === true && count($this->include) > 0) {
foreach($this->include as $includeUrl) {
$includeUrl = rtrim($includeUrl, '/');
if ($includeUrl[strlen($includeUrl) - 1] === '*') {
@@ -64,7 +64,7 @@ class BaseCsrfVerifier implements IMiddleware
break;
}
$skip = !($includeUrl === $request->getUrl()->getOriginalUrl());
$skip = !($includeUrl === rtrim($request->getUrl()->getRelativeUrl(false), '/'));
}
}
@@ -34,6 +34,10 @@ abstract class IpRestrictAccess implements IMiddleware
return true;
}
/**
* @param Request $request
* @throws HttpException
*/
public function handle(Request $request): void
{
if($this->validate((string)$request->getIp()) === false) {
+14 -8
View File
@@ -248,8 +248,9 @@ class Url implements JsonSerializable
public function setQueryString(string $queryString): self
{
$params = [];
parse_str($queryString, $params);
if(parse_str($queryString, $params) !== false) {
if(count($params) > 0) {
return $this->setParams($params);
}
@@ -341,7 +342,7 @@ class Url implements JsonSerializable
*/
public function removeParams(...$names): self
{
$params = array_diff_key($this->getParams(), array_flip($names));
$params = array_diff_key($this->getParams(), array_flip(...$names));
$this->setParams($params);
return $this;
@@ -427,14 +428,18 @@ class Url implements JsonSerializable
/**
* Returns the relative url
*
* @param bool $includeParams
* @return string
*/
public function getRelativeUrl(): string
public function getRelativeUrl($includeParams = true): string
{
$params = $this->getQueryString();
$path = $this->path ?? '/';
$path = $this->path ?? '';
$query = $params !== '' ? '?' . $params : '';
if($includeParams === false) {
return $path;
}
$query = $this->getQueryString() !== '' ? '?' . $this->getQueryString() : '';
$fragment = $this->fragment !== null ? '#' . $this->fragment : '';
return $path . $query . $fragment;
@@ -443,9 +448,10 @@ class Url implements JsonSerializable
/**
* Returns the absolute url
*
* @param bool $includeParams
* @return string
*/
public function getAbsoluteUrl(): string
public function getAbsoluteUrl($includeParams = true): string
{
$scheme = $this->scheme !== null ? $this->scheme . '://' : '';
$host = $this->host ?? '';
@@ -454,7 +460,7 @@ class Url implements JsonSerializable
$pass = $this->password !== null ? ':' . $this->password : '';
$pass = ($user || $pass) ? $pass . '@' : '';
return $scheme . $user . $pass . $host . $port . $this->getRelativeUrl();
return $scheme . $user . $pass . $host . $port . $this->getRelativeUrl($includeParams);
}
/**
@@ -55,7 +55,6 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
public function matchRegex(Request $request, $url): ?bool
{
/* Match on custom defined regular expression */
if ($this->regex === null) {
return null;
}
+20 -2
View File
@@ -76,6 +76,11 @@ abstract class Route implements IRoute
if (is_callable($callback) === true) {
$router->debug('Executing callback');
/* Load class from type hinting */
if (is_array($callback) === true && isset($callback[0], $callback[1]) === true) {
$callback[0] = $router->getClassLoader()->loadClass($callback[0]);
}
/* When the callback is a function */
return $router->getClassLoader()->loadClosure($callback, $parameters);
}
@@ -160,7 +165,7 @@ abstract class Route implements IRoute
foreach ((array)$parameters[1] as $name) {
// Ignore parent parameters
if(isset($groupParameters[$name]) === true) {
if (isset($groupParameters[$name]) === true) {
$lastParams[$name] = $matches[$name];
continue;
}
@@ -244,6 +249,7 @@ abstract class Route implements IRoute
$this->group = $group;
/* Add/merge parent settings with child */
return $this->setSettings($group->toArray(), true);
}
@@ -331,6 +337,17 @@ abstract class Route implements IRoute
*/
public function setNamespace(string $namespace): IRoute
{
$ns = $this->getNamespace();
if ($ns !== null) {
// Don't overwrite namespaces that starts with \
if ($ns[0] !== '\\') {
$namespace .= '\\' . $ns;
} else {
$namespace = $ns;
}
}
$this->namespace = $namespace;
return $this;
@@ -401,7 +418,7 @@ abstract class Route implements IRoute
*/
public function setSettings(array $settings, bool $merge = false): IRoute
{
if ($this->namespace === null && isset($settings['namespace']) === true) {
if (isset($settings['namespace']) === true) {
$this->setNamespace($settings['namespace']);
}
@@ -576,6 +593,7 @@ abstract class Route implements IRoute
public function setFilterEmptyParams(bool $enabled): IRoute
{
$this->filterEmptyParams = $enabled;
return $this;
}
@@ -183,7 +183,6 @@ class RouteGroup extends Route implements IGroupRoute
*/
public function setSettings(array $settings, bool $merge = false): IRoute
{
if (isset($settings['prefix']) === true) {
$this->setPrefix($settings['prefix'] . $this->prefix);
}
+1 -1
View File
@@ -509,7 +509,7 @@ class Router
]);
/* @var $handler IExceptionHandler */
foreach ($this->exceptionHandlers as $key => $handler) {
foreach (array_reverse($this->exceptionHandlers) as $key => $handler) {
if (is_object($handler) === false) {
$handler = new $handler();
+10 -28
View File
@@ -4,8 +4,8 @@
* Router helper class
* ---------------------------
*
* This class is added so calls can be made statically like Router::get() making the code look pretty.
* It also adds some extra functionality like default-namespace.
* This class is added so calls can be made statically like SimpleRouter::get() making the code look pretty.
* It also adds some extra functionality like default-namespace etc.
*/
namespace Pecee\SimpleRouter;
@@ -348,7 +348,7 @@ class SimpleRouter
* @param array|null $settings
* @return RouteUrl|IRoute
*/
public static function match(array $requestMethods, string $url, $callback, array $settings = null)
public static function match(array $requestMethods, string $url, $callback, array $settings = null): IRoute
{
$route = new RouteUrl($url, $callback);
$route->setRequestMethods($requestMethods);
@@ -368,7 +368,7 @@ class SimpleRouter
* @param array|null $settings
* @return RouteUrl|IRoute
*/
public static function all(string $url, $callback, array $settings = null)
public static function all(string $url, $callback, array $settings = null): IRoute
{
$route = new RouteUrl($url, $callback);
@@ -387,7 +387,7 @@ class SimpleRouter
* @param array|null $settings
* @return RouteController|IRoute
*/
public static function controller(string $url, string $controller, array $settings = null)
public static function controller(string $url, string $controller, array $settings = null): IRoute
{
$route = new RouteController($url, $controller);
@@ -406,7 +406,7 @@ class SimpleRouter
* @param array|null $settings
* @return RouteResource|IRoute
*/
public static function resource(string $url, string $controller, array $settings = null)
public static function resource(string $url, string $controller, array $settings = null): IRoute
{
$route = new RouteResource($url, $controller);
@@ -425,16 +425,11 @@ class SimpleRouter
*/
public static function error(Closure $callback): CallbackExceptionHandler
{
$routes = static::router()->getRoutes();
$callbackHandler = new CallbackExceptionHandler($callback);
$group = new RouteGroup();
$group->addExceptionHandler($callbackHandler);
array_unshift($routes, $group);
static::router()->setRoutes($routes);
static::router()->addRoute(
(new RouteGroup())->addExceptionHandler($callbackHandler)
);
return $callbackHandler;
}
@@ -512,20 +507,7 @@ class SimpleRouter
public static function addDefaultNamespace(IRoute $route): IRoute
{
if (static::$defaultNamespace !== null) {
$ns = static::$defaultNamespace;
$namespace = $route->getNamespace();
if ($namespace !== null) {
// Don't overwrite namespaces that starts with \
if ($namespace[0] !== '\\') {
$ns .= '\\' . $namespace;
} else {
$ns = $namespace;
}
}
$route->setNamespace($ns);
$route->setNamespace(static::$defaultNamespace);
}
return $route;
@@ -16,11 +16,11 @@ class CustomClassLoader implements \Pecee\SimpleRouter\ClassLoader\IClassLoader
*/
public function loadClassMethod($class, string $method, array $parameters)
{
return call_user_func_array([$class, $method], ['result' => true]);
return call_user_func_array([$class, $method], [true]);
}
public function loadClosure(callable $closure, array $parameters)
{
return call_user_func_array($closure, ['result' => true]);
return call_user_func_array($closure, [true]);
}
}
@@ -19,10 +19,29 @@ class RouterCallbackExceptionHandlerTest extends \PHPUnit\Framework\TestCase
throw new ExceptionHandlerException();
});
TestRouter::debugNoReset('/404-url', 'get');
TestRouter::router()->reset();
TestRouter::debug('/404-url');
}
$this->assertTrue(true);
public function testExceptionHandlerCallback() {
TestRouter::group(['prefix' => null], function() {
TestRouter::get('/', function() {
return 'Hello world';
});
TestRouter::get('/not-found', 'DummyController@method1');
TestRouter::error(function(\Pecee\Http\Request $request, \Exception $exception) {
if($exception instanceof \Pecee\SimpleRouter\Exceptions\NotFoundHttpException && $exception->getCode() === 404) {
return $request->setRewriteCallback(static function() {
return 'success';
});
}
});
});
$result = TestRouter::debugOutput('/thisdoes-not/existssss', 'get');
$this->assertEquals('success', $result);
}
}
@@ -3,20 +3,20 @@
require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php';
class GroupTest extends \PHPUnit\Framework\TestCase
class RouterGroupTest extends \PHPUnit\Framework\TestCase
{
public function testGroupLoad()
{
$result = false;
TestRouter::group(['prefix' => '/group'], function () use(&$result) {
TestRouter::group(['prefix' => '/group'], function () use (&$result) {
$result = true;
});
try {
TestRouter::debug('/', 'get');
} catch(\Exception $e) {
} catch (\Exception $e) {
}
$this->assertTrue($result);
@@ -81,4 +81,40 @@ class GroupTest extends \PHPUnit\Framework\TestCase
}
public function testNamespaceExtend()
{
TestRouter::group(['namespace' => '\My\Namespace'], function () use (&$result) {
TestRouter::group(['namespace' => 'Service'], function () use (&$result) {
TestRouter::get('/test', function () use (&$result) {
return \Pecee\SimpleRouter\SimpleRouter::router()->getRequest()->getLoadedRoute()->getNamespace();
});
});
});
$namespace = TestRouter::debugOutput('/test');
$this->assertEquals('\My\Namespace\Service', $namespace);
}
public function testNamespaceOverwrite()
{
TestRouter::group(['namespace' => '\My\Namespace'], function () use (&$result) {
TestRouter::group(['namespace' => '\Service'], function () use (&$result) {
TestRouter::get('/test', function () use (&$result) {
return \Pecee\SimpleRouter\SimpleRouter::router()->getRequest()->getLoadedRoute()->getNamespace();
});
});
});
$namespace = TestRouter::debugOutput('/test');
$this->assertEquals('\Service', $namespace);
}
}
@@ -49,9 +49,9 @@ class RouterRewriteTest extends \PHPUnit\Framework\TestCase
}
$expectedStack = [
ExceptionHandlerFirst::class,
ExceptionHandlerSecond::class,
ExceptionHandlerThird::class,
ExceptionHandlerSecond::class,
ExceptionHandlerFirst::class,
];
$this->assertEquals($expectedStack, $stack);