Skip to content
Open
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
34 changes: 2 additions & 32 deletions system/HTTP/FormRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,49 +178,19 @@ protected function failedAuthorization(): ResponseInterface
*
* @return array<string, mixed>
*/
public function validated(): array
public function getValidated(): array
{
return $this->validatedData;
}

/**
* Returns the validated data as a typed input object.
*/
public function validatedInput(): ValidatedInput
public function getValidatedInput(): ValidatedInput
{
return service('inputdatafactory')->createValidated($this->validatedData);
}

/**
* Returns a single validated field value by name, or the default value
* if the field is not present in the validated data.
*
* Supports dot-array syntax for nested validated data.
*/
public function getValidated(string $key, mixed $default = null): mixed
{
helper('array');

if (! dot_array_has($key, $this->validatedData)) {
return $default;
}

return dot_array_search($key, $this->validatedData);
}

/**
* Returns true when the named field exists in the validated data, even if
* its value is null.
*
* Supports dot-array syntax for nested validated data.
*/
public function hasValidated(string $key): bool
{
helper('array');

return dot_array_has($key, $this->validatedData);
}

/**
* Returns the data to be validated.
*
Expand Down
8 changes: 4 additions & 4 deletions tests/_support/Controllers/FormRequestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,23 @@ class FormRequestController extends Controller
*/
public function index(string $id, ValidPostFormRequest $request, string $format = 'json'): string
{
return json_encode(['id' => $id, 'format' => $format, 'data' => $request->validated()]);
return json_encode(['id' => $id, 'format' => $format, 'data' => $request->getValidated()]);
}

/**
* Receives only a FormRequest (no route params).
*/
public function store(ValidPostFormRequest $request): string
{
return json_encode($request->validated());
return json_encode($request->getValidated());
}

/**
* Receives a route param alongside a FormRequest.
*/
public function update(string $id, ValidPostFormRequest $request): string
{
return json_encode(['id' => $id, 'data' => $request->validated()]);
return json_encode(['id' => $id, 'data' => $request->getValidated()]);
}

/**
Expand All @@ -61,7 +61,7 @@ public function show(string $id): string
*/
public function search(ValidPostFormRequest $request, string ...$tags): string
{
return json_encode(['tags' => $tags, 'data' => $request->validated()]);
return json_encode(['tags' => $tags, 'data' => $request->getValidated()]);
}

/**
Expand Down
112 changes: 25 additions & 87 deletions tests/system/HTTP/FormRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@ public function rules(): array
};
}

public function testValidatedReturnsEmptyArrayBeforeResolution(): void
public function testGetValidatedReturnsEmptyArrayBeforeResolution(): void
{
$formRequest = $this->makeFormRequest($this->makeRequest());

$this->assertSame([], $formRequest->validated());
$this->assertSame([], $formRequest->getValidated());
}

// -------------------------------------------------------------------------
Expand All @@ -167,11 +167,11 @@ public function testResolveRequestPassesWithValidData(): void

$this->assertSame(
['title' => 'Hello World', 'body' => 'Some body text'],
$formRequest->validated(),
$formRequest->getValidated(),
);
}

public function testValidatedReturnsOnlyFieldsCoveredByRules(): void
public function testGetValidatedReturnsOnlyFieldsCoveredByRules(): void
{
service('superglobals')->setPost('title', 'Hello World');
service('superglobals')->setPost('body', 'Some body text');
Expand All @@ -180,81 +180,14 @@ public function testValidatedReturnsOnlyFieldsCoveredByRules(): void
$formRequest = $this->makeFormRequest($this->makeRequest());
$formRequest->resolveRequest();

$validated = $formRequest->validated();
$validated = $formRequest->getValidated();

$this->assertArrayHasKey('title', $validated);
$this->assertArrayHasKey('body', $validated);
$this->assertArrayNotHasKey('extra_field', $validated);
}

// -------------------------------------------------------------------------
// Explicit access to validated fields
// -------------------------------------------------------------------------

public function testGetValidatedReturnsValidatedFieldValue(): void
{
service('superglobals')->setPost('title', 'Hello World');
service('superglobals')->setPost('body', 'Some body text');

$formRequest = new ValidPostFormRequest($this->makeRequest());
$formRequest->resolveRequest();

$this->assertSame('Hello World', $formRequest->getValidated('title'));
$this->assertSame('Some body text', $formRequest->getValidated('body'));
}

public function testGetValidatedReturnsNullForMissingField(): void
{
service('superglobals')->setPost('title', 'Hello World');
service('superglobals')->setPost('body', 'Some body text');

$formRequest = new ValidPostFormRequest($this->makeRequest());
$formRequest->resolveRequest();

$this->assertNull($formRequest->getValidated('nonexistent'));
}

public function testGetValidatedReturnsDefaultForMissingField(): void
{
service('superglobals')->setPost('title', 'Hello World');
service('superglobals')->setPost('body', 'Some body text');

$formRequest = new ValidPostFormRequest($this->makeRequest());
$formRequest->resolveRequest();

$this->assertSame('fallback', $formRequest->getValidated('nonexistent', 'fallback'));
}

public function testGetValidatedReturnsNullBeforeValidationRuns(): void
{
$formRequest = new ValidPostFormRequest($this->makeRequest());

$this->assertNull($formRequest->getValidated('title'));
}

public function testHasValidatedReturnsTrueForValidatedField(): void
{
service('superglobals')->setPost('title', 'Hello World');
service('superglobals')->setPost('body', 'Some body text');

$formRequest = new ValidPostFormRequest($this->makeRequest());
$formRequest->resolveRequest();

$this->assertTrue($formRequest->hasValidated('title'));
}

public function testHasValidatedReturnsFalseForMissingField(): void
{
service('superglobals')->setPost('title', 'Hello World');
service('superglobals')->setPost('body', 'Some body text');

$formRequest = new ValidPostFormRequest($this->makeRequest());
$formRequest->resolveRequest();

$this->assertFalse($formRequest->hasValidated('nonexistent'));
}

public function testGetValidatedAndHasValidatedSupportDotSyntax(): void
public function testGetValidatedReturnsNestedValidatedData(): void
{
service('superglobals')->setPost('post', [
'title' => 'Hello World',
Expand All @@ -275,12 +208,20 @@ public function rules(): array

$formRequest->resolveRequest();

$this->assertSame('Hello World', $formRequest->getValidated('post.title'));
$this->assertSame('hello-world', $formRequest->getValidated('post.meta.slug'));
$this->assertTrue($formRequest->hasValidated('post.meta.slug'));
$this->assertSame(
[
'post' => [
'title' => 'Hello World',
'meta' => [
'slug' => 'hello-world',
],
],
],
$formRequest->getValidated(),
);
}

public function testHasValidatedReturnsTrueForNullValidatedField(): void
public function testGetValidatedReturnsNullValidatedField(): void
{
service('superglobals')->setServer('CONTENT_TYPE', 'application/json');

Expand All @@ -293,21 +234,18 @@ public function rules(): array

$formRequest->resolveRequest();

$this->assertSame(['note' => null], $formRequest->validated());
$this->assertNull($formRequest->getValidated('note'));
$this->assertNull($formRequest->getValidated('note', 'fallback'));
$this->assertTrue($formRequest->hasValidated('note'));
$this->assertSame(['note' => null], $formRequest->getValidated());
}

public function testValidatedInputReturnsValidatedInputObject(): void
public function testGetValidatedInputReturnsValidatedInputObject(): void
{
service('superglobals')->setPost('title', 'Hello World');
service('superglobals')->setPost('body', 'Some body text');

$formRequest = new ValidPostFormRequest($this->makeRequest());
$formRequest->resolveRequest();

$input = $formRequest->validatedInput();
$input = $formRequest->getValidatedInput();

$this->assertInstanceOf(ValidatedInput::class, $input);
$this->assertSame('Hello World', $input->get('title'));
Expand Down Expand Up @@ -343,7 +281,7 @@ protected function prepareForValidation(array $data): array
$this->assertNotInstanceOf(ResponseInterface::class, $formRequest->resolveRequest());

$this->assertTrue($formRequest::$prepareCalled);
$this->assertSame('Hi extended', $formRequest->validated()['title']);
$this->assertSame('Hi extended', $formRequest->getValidated()['title']);
}

// -------------------------------------------------------------------------
Expand Down Expand Up @@ -499,7 +437,7 @@ protected function validationData(): array

$this->assertNotInstanceOf(ResponseInterface::class, $formRequest->resolveRequest());

$this->assertSame('Injected Title', $formRequest->validated()['title']);
$this->assertSame('Injected Title', $formRequest->getValidated()['title']);
}

public function testCustomFailedValidationIsRespected(): void
Expand Down Expand Up @@ -708,7 +646,7 @@ public function testClosureRouteWithFormRequestIsInjected(): void

$routes = service('routes');
$routes->setAutoRoute(false);
$routes->add('closure/(:segment)', static fn (string $id, ValidPostFormRequest $request): string => json_encode(['id' => $id, 'data' => $request->validated()]));
$routes->add('closure/(:segment)', static fn (string $id, ValidPostFormRequest $request): string => json_encode(['id' => $id, 'data' => $request->getValidated()]));

$router = service('router', $routes, service('incomingrequest'));
Services::injectMock('router', $router);
Expand Down Expand Up @@ -781,7 +719,7 @@ public function testUnauthorizedFormRequestReturns403(): void
}

// -------------------------------------------------------------------------
// Integration: validated() only returns fields declared in rules()
// Integration: getValidated() only returns fields declared in rules()
// -------------------------------------------------------------------------

#[RunInSeparateProcess]
Expand Down
22 changes: 11 additions & 11 deletions user_guide_src/source/incoming/form_requests.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,26 +49,26 @@ JSON/AJAX requests - the method body is never reached.
Accessing Validated Data
************************

``validated()`` returns an array containing only the fields that were declared
``getValidated()`` returns an array containing only the fields that were declared
in ``rules()``. Fields submitted by the client that are not covered by a rule
are silently discarded, protecting against mass-assignment.

.. literalinclude:: form_requests/009.php
:lines: 2-

Use ``getValidated()`` to read a single validated field and ``hasValidated()``
to check whether a validated key exists, including keys whose value is
``null``. Both methods support dot-array syntax for nested validated data:
Use ``getValidatedInput()`` when you want to read a single validated field or
check whether a validated key exists, including keys whose value is ``null``.
The input object supports dot-array syntax for nested validated data:

.. literalinclude:: form_requests/014.php
:lines: 2-

Typed Validated Input
=====================

``validatedInput()`` returns the same validated data as a typed input object.
This keeps the array-based APIs unchanged while making common controller values
easier to read after validation has succeeded.
``getValidatedInput()`` returns the same validated data as a typed input object.
This complements ``getValidated()`` by making common controller values easier
to read after validation has succeeded.

After the FormRequest has been validated, read the successful values in the
controller:
Expand All @@ -83,7 +83,7 @@ for the full behavior of the typed input methods.
Accessing Other Request Data
============================

For anything not covered by ``validated()`` - uploaded files, request headers,
For anything not covered by ``getValidated()`` - uploaded files, request headers,
the client IP address, raw input, and so on - use ``$this->request`` as usual.
It is the same :doc:`IncomingRequest </incoming/incomingrequest>` instance that
the FormRequest uses internally:
Expand Down Expand Up @@ -171,7 +171,7 @@ normalized phone numbers, or trimmed strings.
:lines: 2-

.. note:: ``old()`` returns the original submitted input, not the normalized
values. Use ``validated()`` to access the processed data after a successful
values. Use ``getValidated()`` to access the processed data after a successful
request. If you need ``old()`` to reflect normalized values, see
:ref:`form-request-flash-normalized`.

Expand Down Expand Up @@ -245,8 +245,8 @@ whose type extends ``FormRequest``:
rules are applied.
#. ``run()`` executes the validation rules. If it fails, ``failedValidation()``
is called, and its response is returned to the client.
#. The validated data is stored internally and available via ``validated()``,
``validatedInput()``, ``getValidated()``, and ``hasValidated()``.
#. The validated data is stored internally and available via ``getValidated()``
and ``getValidatedInput()``.
#. The resolved FormRequest object is injected into the controller method or
closure.

Expand Down
4 changes: 2 additions & 2 deletions user_guide_src/source/incoming/form_requests/002.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class Posts extends BaseController
{
public function store(StorePostRequest $request): string
{
// $request->validated() returns only the fields declared in rules().
$data = $request->validated();
// $request->getValidated() returns only the fields declared in rules().
$data = $request->getValidated();

// save to database

Expand Down
2 changes: 1 addition & 1 deletion user_guide_src/source/incoming/form_requests/003.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Posts extends BaseController
// Route parameters come first; FormRequest follows.
public function update(int $id, UpdatePostRequest $request): string
{
$data = $request->validated();
$data = $request->getValidated();

// update post $id with $data

Expand Down
2 changes: 1 addition & 1 deletion user_guide_src/source/incoming/form_requests/009.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?php

$data = $request->validated();
$data = $request->getValidated();
// ['title' => 'My post title', 'body' => 'Body text']
2 changes: 1 addition & 1 deletion user_guide_src/source/incoming/form_requests/010.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Posts extends BaseController
{
public function store(StorePostRequest $request): string
{
$data = $request->validated();
$data = $request->getValidated();
$files = $this->request->getFiles();

// ...
Expand Down
Loading
Loading