diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index de2ef7d62472..6bb8faad5d83 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -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']))); + } + /** * Get data to be validated from the request. * diff --git a/tests/Foundation/FoundationFormRequestTest.php b/tests/Foundation/FoundationFormRequestTest.php index 3af04233cc2c..95d91533bfe2 100644 --- a/tests/Foundation/FoundationFormRequestTest.php +++ b/tests/Foundation/FoundationFormRequestTest.php @@ -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() { @@ -107,7 +192,7 @@ public function authorize() } } -class FoundationTestFormRequestForbiddenStub extends \Illuminate\Foundation\Http\FormRequest +class FoundationTestFormRequestForbiddenStub extends FormRequest { public function rules() { @@ -119,7 +204,7 @@ public function authorize() return false; } } -class FoundationTestFormRequestHooks extends \Illuminate\Foundation\Http\FormRequest +class FoundationTestFormRequestHooks extends FormRequest { public function rules() {