Skip to content

Commit

Permalink
handle mismatch reason
Browse files Browse the repository at this point in the history
  • Loading branch information
iwyg committed Feb 2, 2016
1 parent 669b389 commit be06eee
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 39 deletions.
56 changes: 29 additions & 27 deletions src/Matcher/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,39 +20,19 @@
*/
class Context implements ContextInterface
{
/**
* type
*
* @var int
*/
/** @var int */
private $type;

/**
* name
*
* @var string
*/
/** @var string */
private $name;

/**
* path
*
* @var string
*/
/** @var string */
private $path;

/**
* handler
*
* @var mixed
*/
/** @var mixed */
private $handler;

/**
* parameters
*
* @var array
*/
/** @var array */
private $vars;

/**
Expand All @@ -63,8 +43,6 @@ class Context implements ContextInterface
* @param string $url
* @param mixed $handler
* @param array $vars
*
* @return void
*/
public function __construct($type, $name, $url, $handler, array $vars = [])
{
Expand All @@ -83,6 +61,30 @@ public function isMatch()
return RequestMatcherInterface::MATCH === $this->type;
}

/**
* {@inheritdoc}
*/
public function isHostMissmatch()
{
return RequestMatcherInterface::NOMATCH_HOST === $this->type;
}

/**
* {@inheritdoc}
*/
public function isMethodMissmatch()
{
return RequestMatcherInterface::NOMATCH_METHOD === $this->type;
}

/**
* {@inheritdoc}
*/
public function isSchemeMissMatch()
{
return RequestMatcherInterface::NOMATCH_SCHEME === $this->type;
}

/**
* {@inheritdoc}
*/
Expand Down
17 changes: 16 additions & 1 deletion src/Matcher/ContextInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,25 @@ interface ContextInterface
/**
* isMatch
*
* @return boolean
* @return bool
*/
public function isMatch();

/**
* @return bool
*/
public function isHostMissmatch();

/**
* @return bool
*/
public function isMethodMissmatch();

/**
* @return bool
*/
public function isSchemeMissMatch();

/**
* getName
*
Expand Down
44 changes: 44 additions & 0 deletions src/Matcher/MatcherTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Lucid\Mux\Matcher;

use Lucid\Mux\RouteInterface;
use Lucid\Mux\RouteContextInterface as RouteContext;
use Lucid\Mux\RouteCollectionInterface;
use Lucid\Mux\Request\ContextInterface as Request;

Expand All @@ -37,6 +38,49 @@ private function filterByMethodAndScheme(RouteCollectionInterface $routes, Reque
return $routes->findByMethod($context->getMethod())->findByScheme($context->getScheme());
}

/**
* getMatchFailureReason
*
* @param array $nomatch
* @param Request $request
*
* @return int
*/
private function getMatchFailureReason(array $nomatch, Request $request)
{
$path = $request->getPath();

$reduce = array_filter($nomatch, function ($route) use ($path) {
return (bool)preg_match_all($route->getContext()->getRegex(), $path);
});

foreach ($reduce as $name => $route) {

if (!$this->matchHost($route->getContext(), $request, $route->getHost())) {
return RequestMatcherInterface::NOMATCH_HOST;
}

if (!$route->hasScheme($request->getScheme())) {
return RequestMatcherInterface::NOMATCH_SCHEME;
}

if (!$route->hasMethod($request->getMethod())) {
return RequestMatcherInterface::NOMATCH_METHOD;
}
}

return RequestMatcherInterface::NOMATCH;
}

private function matchHost(RouteContext $ctx, Request $request, $host = null)
{
if (null === $host) {
return true;
}

return (bool)preg_match_all($ctx->getHostRegex(), $request->getHost());
}

/**
* getMatchedParams
*
Expand Down
19 changes: 11 additions & 8 deletions src/Matcher/RequestMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,21 @@ class RequestMatcher implements RequestMatcherInterface
public function matchRequest(Request $request, RouteCollectionInterface $routes)
{
$path = $request->getPath();
$routes = $this->filterByMethodAndScheme($routes, $request);
$filtered = $this->filterByMethodAndScheme($routes, $request);

if ($routes instanceof CachedCollectionInterface && 0 !== count($r = $route->findByStaticPath($path))) {
$routes = $r;
if ($filtered instanceof CachedCollectionInterface && 0 !== count($r = $route->findByStaticPath($path))) {
$filtered = $r;
}

foreach ($routes->all() as $name => $route) {
$nomatch = array_diff_key($routes->all(), $filtered->all());

foreach ($filtered->all() as $name => $route) {

$rctx = $route->getContext();

// does it match host?
if (null !== ($host = $route->getHost())
&& !(bool)preg_match_all($rctx->getHostRegex(), $request->getHost(), PREG_SET_ORDER)
) {
if (!$this->matchHost($rctx, $request, $route->getHost())) {
$nomatch[$name] = $route;
continue;
}

Expand All @@ -67,8 +68,10 @@ public function matchRequest(Request $request, RouteCollectionInterface $routes)

return new MatchContext(self::MATCH, $name, $path, $handler, $vars);
}

$nomatch[$name] = $route;
}

return new MatchContext(self::NOMATCH, null, null, null);
return new MatchContext($this->getMatchFailureReason($nomatch, $request), null, null, null);
}
}
17 changes: 14 additions & 3 deletions src/Matcher/RequestMatcherInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,27 @@
*/
interface RequestMatcherInterface
{
const MATCH = 200;
/** @var int */
const MATCH = 1;

const NOMATCH = 500;
/** @var int */
const NOMATCH = -1;

/** @var int */
const NOMATCH_METHOD = -2;

/** @var int */
const NOMATCH_HOST = -3;

/** @var int */
const NOMATCH_SCHEME = -4;

/**
* matchRequest
*
* @param RequestContextInterface $context
*
* @return array
* @return ContextInterface
*/
public function matchRequest(Request $context, RouteCollectionInterface $routes);
}
51 changes: 51 additions & 0 deletions tests/Matcher/ContextTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace Lucid\Mux\Tests\Matcher;

use Lucid\Mux\Matcher\Context;
use Lucid\Mux\Matcher\ContextInterface;
use Lucid\Mux\Matcher\RequestMatcherInterface as Matcher;

class ContextTest extends \PHPUnit_Framework_TestCase
{
/** @test */
public function contextWillReturnProperties()
{
$ctx = new Context(Matcher::MATCH, 'index', '/', 'action', $vars = ['id' => 12]);
$this->assertTrue($ctx->isMatch());
$this->assertEquals('/', $ctx->getPath());
$this->assertEquals('index', $ctx->getName());
$this->assertEquals('action', $ctx->getHandler());
$this->assertSame($vars, $ctx->getVars());
}

/** @test */
public function itShouldBeInstantiable()
{
$this->assertInstanceOf('Lucid\Mux\Matcher\ContextInterface', new Context(Matcher::NOMATCH, null, null, null));
}

/** @test */
public function itShouldBeMatchFailure()
{
$this->assertFalse((new Context(Matcher::NOMATCH, null, null, null))->isMatch());
}

/** @test */
public function itShouldBeMethodFailure()
{
$this->assertTrue(($ctx = new Context(Matcher::NOMATCH_METHOD, null, null, null))->isMethodMissmatch());
}

/** @test */
public function itShouldBeHostFailure()
{
$this->assertTrue(($ctx = new Context(Matcher::NOMATCH_HOST, null, null, null))->isHostMissmatch());
}

/** @test */
public function itShouldBeSchemeFailure()
{
$this->assertTrue(($ctx = new Context(Matcher::NOMATCH_SCHEME, null, null, null))->isSchemeMissmatch());
}
}
57 changes: 57 additions & 0 deletions tests/Matcher/RequestMatcherTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,63 @@ public function itShouldMatchRequests()
$this->assertTrue($ret->isMatch());
}

/** @test */
public function itShouldReturnCorrectMissmatchReason()
{
$matcher = new Matcher();

$routes = new Routes;

$routes->add('user.show', new Route('/user/{id}', 'showUserAction', ['GET'], 'example.com'));
$routes->add('user.delete', new Route('/user/{id}', 'deleteUserAction', ['DELETE'], 'example.{tld}'));

$request = $this->mockRequest();

$request->method('getMethod')->willReturn('PATCH');
$request->method('getPath')->willReturn('/user/12');
$request->method('getScheme')->willReturn('http');
$request->method('getHost')->willReturn('example.com');

$result = $matcher->matchRequest($request, $routes);

$this->assertTrue($result->isMethodMissmatch(), 'Reason should be method missmatch.');

// replace delete
$routes = new Routes;

$routes->add(
'user_delete',
new Route('/user/{id}', 'deleteUserAction', ['DELETE'], 'example.org')
);

$request = $this->mockRequest();
$request->method('getMethod')->willReturn('DELETE');
$request->method('getPath')->willReturn('/user/12');
$request->method('getScheme')->willReturn('http');
$request->method('getHost')->willReturn('example.com');

$result = $matcher->matchRequest($request, $routes);

$this->assertTrue($result->isHostMissmatch(), 'Reason should be host missmatch.');

// replace delete
$routes = new Routes;

$routes->add(
'index',
new Route('/', 'indexAction', ['GET'], null, null, null, ['https'])
);

$request = $this->mockRequest();
$request->method('getMethod')->willReturn('GET');
$request->method('getPath')->willReturn('/');
$request->method('getScheme')->willReturn('http');

$result = $matcher->matchRequest($request, $routes);

$this->assertTrue($result->isSchemeMissmatch(), 'Reason should be scheme missmatch.');
}

private function mockRoute()
{
return $this->getMockbuilder('Lucid\Mux\Route')
Expand Down

0 comments on commit be06eee

Please sign in to comment.