Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.5] Add a "validated" method to the form request #19112

Merged
merged 2 commits into from
May 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/Illuminate/Foundation/Http/FormRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ protected function createDefaultValidator(ValidationFactory $factory)
);
}

/**
* Get the validated data from the request.
*
* @return array
*/
public function validated()
{
return $this->only(array_keys($this->container->call([$this, 'rules'])));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JosephSilber why not calling $this->rules() directly as the object is already instantiated?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rodrigopedra $this->container->call([$this, 'rules']) calls the method and inject any dependencies it has declared, as method parantheses. $this->rules() doesn't.

}

/**
* Get data to be validated from the request.
*
Expand Down
199 changes: 142 additions & 57 deletions tests/Foundation/FoundationFormRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,99 +2,184 @@

namespace Illuminate\Tests\Foundation;

use Exception;
use Mockery as m;
use PHPUnit\Framework\TestCase;
use Illuminate\Routing\Redirector;
use Illuminate\Container\Container;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Http\RedirectResponse;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\ValidationException;
use Illuminate\Contracts\Translation\Translator;
use Illuminate\Validation\Factory as ValidationFactory;
use Illuminate\Contracts\Validation\Factory as ValidationFactoryContract;

class FoundationFormRequestTest extends TestCase
{
protected $mocks = [];

public function tearDown()
{
m::close();

$this->mocks = [];
}

public function testValidateFunctionRunsValidatorOnSpecifiedRules()
public function test_validated_method_returns_the_validated_data()
{
$request = FoundationTestFormRequestStub::create('/', 'GET', ['name' => 'abigail']);
$request->setContainer($container = new Container);
$factory = m::mock('Illuminate\Validation\Factory');
$factory->shouldReceive('make')->once()->with(['name' => 'abigail'], ['name' => 'required'], [], [])->andReturn(
$validator = m::mock('Illuminate\Validation\Validator')
);
$container->instance('Illuminate\Contracts\Validation\Factory', $factory);
$validator->shouldReceive('passes')->once()->andReturn(true);
$request = $this->createRequest(['name' => 'specified', 'with' => 'extras']);

$request->validate();

$request->validate($factory);
$this->assertEquals(['name' => 'specified'], $request->validated());
}

/**
* @expectedException \Illuminate\Validation\ValidationException
*/
public function testValidateFunctionThrowsValidationExceptionIfValidationFails()
public function test_validate_throws_when_validation_fails()
{
$request = m::mock('Illuminate\Tests\Foundation\FoundationTestFormRequestStub[response]');
$request->initialize(['name' => null]);
$request->setContainer($container = new Container);
$factory = m::mock('Illuminate\Validation\Factory');
$factory->shouldReceive('make')->once()->with(['name' => null], ['name' => 'required'], [], [])->andReturn(
$validator = m::mock('Illuminate\Validation\Validator')
);
$container->instance('Illuminate\Contracts\Validation\Factory', $factory);
$validator->shouldReceive('passes')->once()->andReturn(false);
$validator->shouldReceive('getMessageBag')->once()->andReturn($messages = m::mock('Illuminate\Support\MessageBag'));
$messages->shouldReceive('toArray')->once()->andReturn(['name' => ['Name required']]);
$request->shouldReceive('response')->once()->andReturn(new \Illuminate\Http\Response);
$request = $this->createRequest(['no' => 'name']);

$request->validate($factory);
$this->mocks['redirect']->shouldReceive('withInput->withErrors');

$request->validate();
}

/**
* @expectedException \Illuminate\Auth\Access\AuthorizationException
*/
public function testValidateFunctionThrowsHttpResponseExceptionIfAuthorizationFails()
public function test_validate_method_throws_when_authorization_fails()
{
$this->createRequest([], FoundationTestFormRequestForbiddenStub::class)->validate();
}

public function test_redirect_response_is_properly_created_with_given_errors()
{
$request = $this->createRequest();

$this->mocks['redirect']->shouldReceive('withInput')->andReturnSelf();

$this->mocks['redirect']
->shouldReceive('withErrors')
->with(['name' => ['error']], 'default')
->andReturnSelf();

$e = $this->catchException(ValidationException::class, function () use ($request) {
$request->validate();
});

$this->assertInstanceOf(RedirectResponse::class, $e->getResponse());
}

public function test_prepare_for_validation_runs_before_validation()
{
$this->createRequest([], FoundationTestFormRequestHooks::class)->validate();
}

/**
* Catch the given exception thrown from the executor, and return it.
*
* @param string $class
* @param \Closure $excecutor
* @return \Exception
*/
protected function catchException($class, $excecutor)
{
try {
$excecutor();
} catch (Exception $e) {
if (is_a($e, $class)) {
return $e;
}

throw $e;
}

throw new Exception("No exception thrown. Expected exception {$class}");
}

/**
* Create a new request of the given type.
*
* @param array $payload
* @param string $class
* @return \Illuminate\Foundation\Http\FormRequest
*/
protected function createRequest($payload = [], $class = FoundationTestFormRequestStub::class)
{
$container = tap(new Container, function ($container) {
$container->instance(
ValidationFactoryContract::class,
$this->createValidationFactory($container)
);
});

$request = $class::create('/', 'GET', $payload);

return $request->setRedirector($this->createMockRedirector($request))
->setContainer($container);
}

/**
* Create a new validation factory.
*
* @param \Illuminate\Container\Container $container
* @return \Illuminate\Validation\Factory
*/
protected function createValidationFactory($container)
{
$request = m::mock('Illuminate\Tests\Foundation\FoundationTestFormRequestForbiddenStub[forbiddenResponse]');
$request->initialize(['name' => null]);
$request->setContainer($container = new Container);
$factory = m::mock('Illuminate\Validation\Factory');
$factory->shouldReceive('make')->once()->with(['name' => null], ['name' => 'required'], [], [])->andReturn(
$validator = m::mock('Illuminate\Validation\Validator')
);
$container->instance('Illuminate\Contracts\Validation\Factory', $factory);
$validator->shouldReceive('passes')->never();
$translator = m::mock(Translator::class)->shouldReceive('trans')
->zeroOrMoreTimes()->andReturn('error')->getMock();

$request->validate($factory);
return new ValidationFactory($translator, $container);
}

public function testRedirectResponseIsProperlyCreatedWithGivenErrors()
/**
* Create a mock redirector.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Routing\Redirector
*/
protected function createMockRedirector($request)
{
$request = FoundationTestFormRequestStub::create('/', 'GET');
$request->setRedirector($redirector = m::mock('Illuminate\Routing\Redirector'));
$redirector->shouldReceive('to')->once()->with('previous')->andReturn($response = m::mock('Illuminate\Http\RedirectResponse'));
$redirector->shouldReceive('getUrlGenerator')->andReturn($url = m::mock('StdClass'));
$url->shouldReceive('previous')->once()->andReturn('previous');
$response->shouldReceive('withInput')->andReturn($response);
$response->shouldReceive('withErrors')->with(['errors'], 'default')->andReturn($response);
$redirector = $this->mocks['redirector'] = m::mock(Redirector::class);

$redirector->shouldReceive('getUrlGenerator')->zeroOrMoreTimes()
->andReturn($generator = $this->createMockUrlGenerator());

$request->response(['errors']);
$redirector->shouldReceive('to')->zeroOrMoreTimes()
->andReturn($this->createMockRedirectResponse());

$generator->shouldReceive('previous')->zeroOrMoreTimes()
->andReturn('previous');

return $redirector;
}

public function testValidateFunctionRunsBeforeValidationFunction()
/**
* Create a mock URL generator.
*
* @return \Illuminate\Routing\UrlGenerator
*/
protected function createMockUrlGenerator()
{
$request = FoundationTestFormRequestHooks::create('/', 'GET', ['name' => 'abigail']);
$request->setContainer($container = new Container);
$factory = m::mock('Illuminate\Validation\Factory');
$factory->shouldReceive('make')->once()->with(['name' => 'Taylor'], ['name' => 'required'], [], [])->andReturn(
$validator = m::mock('Illuminate\Validation\Validator')
);
$container->instance('Illuminate\Contracts\Validation\Factory', $factory);
$validator->shouldReceive('passes')->once()->andReturn(true);
return $this->mocks['generator'] = m::mock(UrlGenerator::class);
}

$request->validate($factory);
/**
* Create a mock redirect response.
*
* @return \Illuminate\Http\RedirectResponse
*/
protected function createMockRedirectResponse()
{
return $this->mocks['redirect'] = m::mock(RedirectResponse::class);
}
}

class FoundationTestFormRequestStub extends \Illuminate\Foundation\Http\FormRequest
class FoundationTestFormRequestStub extends FormRequest
{
public function rules()
{
Expand All @@ -107,7 +192,7 @@ public function authorize()
}
}

class FoundationTestFormRequestForbiddenStub extends \Illuminate\Foundation\Http\FormRequest
class FoundationTestFormRequestForbiddenStub extends FormRequest
{
public function rules()
{
Expand All @@ -119,7 +204,7 @@ public function authorize()
return false;
}
}
class FoundationTestFormRequestHooks extends \Illuminate\Foundation\Http\FormRequest
class FoundationTestFormRequestHooks extends FormRequest
{
public function rules()
{
Expand Down