Laravel Validation validated() 的实现
Reference
- illuminate/validation
- laravel/laravel
Path
vendor/laravel/framework/src/Illuminate/Validation/Validator.php
实现
validated()
- 结合代码可以看出
validated()
方法的核心逻辑在于取值data_get
和赋值Arr::set()
这俩个地方
/**
* Get the attributes and values that were validated.
*
* @return array
*
* @throws \Illuminate\Validation\ValidationException
*/
public function validated()
{
// 检查当前的验证是否通过
if ($this->invalid()) {
throw new ValidationException($this);
}
$results = [];
// 随机字符串 用于给数据赋予默认的值[暂不清楚有啥作用]
$missingValue = Str::random(10);
// $this->getRules() 会获取到所有的验证规则的 key , key 即为我们定义的规则键名
// 这里的 data_get 和 Arr::set 都是自定义的用于获取和定义 item.key 这样形式的数据的辅助函数
foreach (array_keys($this->getRules()) as $key) {
// 获取数据中的键对应的值
$value = data_get($this->getData(), $key, $missingValue);
// 如果值不是随机字符串, 则将值赋予给结果数组
// 那这里也就是说,如果这个键在数据传递的数据中没有定义值,那么就不会被赋值给结果数组
if ($value !== $missingValue) {
Arr::set($results, $key, $value);
}
}
return $results;
}
data_get()
if (! function_exists('data_get')) {
/**
* Get an item from an array or object using "dot" notation.
*
* @param mixed $target
* @param string|array|int $key
* @param mixed $default
* @return mixed
*/
function data_get($target, $key, $default = null)
{
// 如果 key 为 null,则直接返回 target,也就是直接返回原数据
if (is_null($key)) {
return $target;
}
// key 还能是数组吗???这里应该是兼容的其他地方的调用
// validator 这里调用的时候应该是使用后面 explode 的方式
// 为的是处理 类似 user.name 这样的 key
$key = is_array($key) ? $key : explode('.', $key);
// 这里是一个 while 循环,每次循环都会从 key 中取出一个元素
// np 这里将 array 类似为一个队列,不断的从中 pop(shift) 元素,直到为空
while (! is_null($segment = array_shift($key))) {
// 如果当前元素为 * , 对应的是 users.*.name 这样的多维数组的场景
if ($segment === '*') {
// 如果 target 是一个集合,那么就将集合中的每一个元素的 key 对应的值取出来
if ($target instanceof Collection) {
$target = $target->all();
} elseif (! is_array($target)) {
return value($default);
}
$result = [];
foreach ($target as $item) {
// 这里需要注意的事 array_shift 是引用传递参数的
// 也就是说如果最初传递的 参数是 user.*.name -> ["user", "*", "name"],那么当代码执行到此处时 key 经过前面的 pop 到此处其实只有 ["name"] 了
// 递归调用 data_get,将结果放入 result 中, 此时再传递进去的 key 就是数组,正好对应了上面的数据格式兼容设计()
$result[] = data_get($item, $key);
}
// Arr::collapse 顾名思义,将多维数组降低一个维度
// 那么索引数组下同名的 key 值会进行覆盖?
// 啥意思啊??? 类似 user.* 的场景吗 数组?["zhangsan", "lisi", "wangwu"] 这样的场景?
// 当 key 以 * 结尾时,返回当前数组即可,不过要求当前数组机
return in_array('*', $key) ? Arr::collapse($result) : $result;
}
if (Arr::accessible($target) && Arr::exists($target, $segment)) {
// Arr::accessible 判断 $targe 是否实现了数组接口
// Arr::exists 判断 $target 中是否存在 $segment 这个 key
// 如果是数组的话 直接取值就好了
$target = $target[$segment];
} elseif (is_object($target) && isset($target->{$segment})) {
// 如果是对象的话,直接取属性
$target = $target->{$segment};
} else {
// 其他类型的话,直接返回默认值
return value($default);
}
}
return $target;
}
}
Arr::set()
/**
* Set an array item to a given value using "dot" notation.
*
* If no key is given to the method, the entire array will be replaced.
*
* @param array $array
* @param string $key
* @param mixed $value
* @return array
*/
public static function set(&$array, $key, $value)
{
if (is_null($key)) {
return $array = $value;
}
$keys = explode('.', $key);
while (count($keys) > 1) {
$key = array_shift($keys);
// If the key doesn't exist at this depth, we will just create an empty array
// to hold the next value, allowing us to create the arrays to hold final
// values at the correct depth. Then we'll keep digging into the array.
if (! isset($array[$key]) || ! is_array($array[$key])) {
$array[$key] = [];
}
$array = &$array[$key];
}
$array[array_shift($keys)] = $value;
return $array;
}