-
Notifications
You must be signed in to change notification settings - Fork 11k
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
[8.x] Validated subsets #38366
[8.x] Validated subsets #38366
Changes from all commits
d78c056
6ce6e03
550fc31
ca854af
578a76c
0683dfb
fe8c1f6
63f8bc3
7655c97
b6c832e
ffbc5fb
80c67d4
1d658a2
ebff1ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
namespace Illuminate\Contracts\Support; | ||
|
||
use ArrayAccess; | ||
use IteratorAggregate; | ||
|
||
interface ValidatedData extends Arrayable, ArrayAccess, IteratorAggregate | ||
{ | ||
// | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
<?php | ||
|
||
namespace Illuminate\Support; | ||
|
||
use ArrayIterator; | ||
use Illuminate\Contracts\Support\ValidatedData; | ||
use stdClass; | ||
|
||
class ValidatedInput implements ValidatedData | ||
{ | ||
/** | ||
* The underlying input. | ||
* | ||
* @var array | ||
*/ | ||
protected $input; | ||
|
||
/** | ||
* Create a new validated input container. | ||
* | ||
* @param array $input | ||
* @return void | ||
*/ | ||
public function __construct(array $input) | ||
{ | ||
$this->input = $input; | ||
} | ||
|
||
/** | ||
* Get a subset containing the provided keys with values from the input data. | ||
* | ||
* @param array|mixed $keys | ||
* @return array | ||
*/ | ||
public function only($keys) | ||
{ | ||
$results = []; | ||
|
||
$input = $this->input; | ||
|
||
$placeholder = new stdClass; | ||
|
||
foreach (is_array($keys) ? $keys : func_get_args() as $key) { | ||
$value = data_get($input, $key, $placeholder); | ||
|
||
if ($value !== $placeholder) { | ||
Arr::set($results, $key, $value); | ||
} | ||
} | ||
|
||
return $results; | ||
Comment on lines
+37
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason we aren't just hitting the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed that Request's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. one difference that I can think of is passing |
||
} | ||
|
||
/** | ||
* Get all of the input except for a specified array of items. | ||
* | ||
* @param array|mixed $keys | ||
* @return array | ||
*/ | ||
public function except($keys) | ||
{ | ||
$keys = is_array($keys) ? $keys : func_get_args(); | ||
|
||
$results = $this->input; | ||
|
||
Arr::forget($results, $keys); | ||
|
||
return $results; | ||
} | ||
|
||
/** | ||
* Get the input as a collection. | ||
* | ||
* @return \Illuminate\Support\Collection | ||
*/ | ||
public function collect() | ||
{ | ||
return new Collection($this->input); | ||
} | ||
Comment on lines
+76
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ryangjchandler will appreciate this one There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is beautiful. |
||
|
||
/** | ||
* Get the raw, underlying input array. | ||
* | ||
* @return array | ||
*/ | ||
public function all() | ||
{ | ||
return $this->input; | ||
} | ||
|
||
/** | ||
* Get the instance as an array. | ||
* | ||
* @return array | ||
*/ | ||
public function toArray() | ||
{ | ||
return $this->all(); | ||
} | ||
|
||
/** | ||
* Dynamically access input data. | ||
* | ||
* @param string $name | ||
* @return mixed | ||
*/ | ||
public function __get($name) | ||
{ | ||
return $this->input[$name]; | ||
} | ||
|
||
/** | ||
* Dynamically set input data. | ||
* | ||
* @param string $name | ||
* @param mixed $value | ||
* @return mixed | ||
*/ | ||
public function __set($name, $value) | ||
{ | ||
$this->input[$name] = $value; | ||
} | ||
|
||
/** | ||
* Determine if an input key is set. | ||
* | ||
* @return bool | ||
*/ | ||
public function __isset($name) | ||
{ | ||
return isset($this->input[$name]); | ||
} | ||
|
||
/** | ||
* Remove an input key. | ||
* | ||
* @param string $name | ||
* @return void | ||
*/ | ||
public function __unset($name) | ||
{ | ||
unset($this->input[$name]); | ||
} | ||
|
||
/** | ||
* Determine if an item exists at an offset. | ||
* | ||
* @param mixed $key | ||
* @return bool | ||
*/ | ||
#[\ReturnTypeWillChange] | ||
public function offsetExists($key) | ||
{ | ||
return isset($this->input[$key]); | ||
} | ||
|
||
/** | ||
* Get an item at a given offset. | ||
* | ||
* @param mixed $key | ||
* @return mixed | ||
*/ | ||
#[\ReturnTypeWillChange] | ||
public function offsetGet($key) | ||
{ | ||
return $this->input[$key]; | ||
} | ||
|
||
/** | ||
* Set the item at a given offset. | ||
* | ||
* @param mixed $key | ||
* @param mixed $value | ||
* @return void | ||
*/ | ||
#[\ReturnTypeWillChange] | ||
taylorotwell marked this conversation as resolved.
Show resolved
Hide resolved
|
||
public function offsetSet($key, $value) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't an immutable object make sense? A stict guarantee that ValidatedData is the unmodified result of a validator would sometimes be usefull i guess. What i mean is, changing a validated input may make it not the valid anymore. |
||
{ | ||
if (is_null($key)) { | ||
$this->input[] = $value; | ||
} else { | ||
$this->input[$key] = $value; | ||
} | ||
} | ||
|
||
/** | ||
* Unset the item at a given offset. | ||
* | ||
* @param string $key | ||
* @return void | ||
*/ | ||
#[\ReturnTypeWillChange] | ||
public function offsetUnset($key) | ||
{ | ||
unset($this->input[$key]); | ||
} | ||
|
||
/** | ||
* Get an iterator for the input. | ||
* | ||
* @return \ArrayIterator | ||
*/ | ||
taylorotwell marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#[\ReturnTypeWillChange] | ||
public function getIterator() | ||
{ | ||
return new ArrayIterator($this->input); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ | |
use Illuminate\Support\Fluent; | ||
use Illuminate\Support\MessageBag; | ||
use Illuminate\Support\Str; | ||
use Illuminate\Support\ValidatedInput; | ||
use RuntimeException; | ||
use stdClass; | ||
use Symfony\Component\HttpFoundation\File\UploadedFile; | ||
|
@@ -500,6 +501,16 @@ public function validateWithBag(string $errorBag) | |
} | ||
} | ||
|
||
/** | ||
* Get a validated input container for the validated input. | ||
* | ||
* @return \Illuminate\Support\ValidatedInput | ||
*/ | ||
public function safe() | ||
{ | ||
return new ValidatedInput($this->validated()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i have a question ... may i know why not bind the interface to the concrete ValidatedInput instance inside ValidationServiceProvider ... and here call app(ValidatedData::class, ['input' => $thsi->validated()]) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's nice! And also changing the return type to the interface. I mean, we don't need the interface if the implementation is hardcoded to a specific class. |
||
} | ||
|
||
/** | ||
* Get the attributes and values that were validated. | ||
* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
namespace Illuminate\Tests\Support; | ||
|
||
use Illuminate\Support\ValidatedInput; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
class ValidatedInputTest extends TestCase | ||
{ | ||
public function test_can_access_input() | ||
{ | ||
$input = new ValidatedInput(['name' => 'Taylor', 'votes' => 100]); | ||
|
||
$this->assertEquals('Taylor', $input->name); | ||
$this->assertEquals('Taylor', $input['name']); | ||
$this->assertEquals(['name' => 'Taylor'], $input->only(['name'])); | ||
$this->assertEquals(['name' => 'Taylor'], $input->except(['votes'])); | ||
$this->assertEquals(['name' => 'Taylor', 'votes' => 100], $input->all()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any specific reason this isn't an actual collection?
(The only difference is the
only
method working on nested data, which we could easily add to the collection's method, or just override it here)