3.2.2 - Laravel - 5.6 - Route - group属性合并
上一节中 3.2.1 中,我们讲到路由的 group 方法第一步中,涉及到了把 group 的属性 attributes 数据和 groupStack 数组中的最后一个数据合并:再来看下上一节说到的合并代码
public function mergeWithLastGroup($new)
{
return RouteGroup::merge($new, end($this->groupStack));
}
因为这个逻辑规则较多,单独拿出来分析一下。
再次明确一些定义:
1.RouteGroup 是 Route 对象的集合,可以看成是一个路由表,一旦请求 request 过来就是去
RouteGroup 的对象中寻找对应的 route 对象,进行对应的逻辑处理。这些 route 对象就是在上一节说到的 group 方法中注册的。
2.mergeWithLastGroup 的参数 $new
就是在编写定义 group 方法时,同时定义的 group 附带的 namespace,prefix,middleware 等属性 attribute 的集合。
接下来我们就进一步查看一下 RouteGroup 的 merge 方法:
public static function merge($new, $old)
{
if (isset($new['domain'])) {
unset($old['domain']);
}
$new = array_merge(static::formatAs($new, $old), [
'namespace' => static::formatNamespace($new, $old),
'prefix' => static::formatPrefix($new, $old),
'where' => static::formatWhere($new, $old),
]);
return array_merge_recursive(Arr::except(
$old, ['namespace', 'prefix', 'where', 'as']
), $new);
}
分三步:
1. 参数 $new 就是 group 定义时候的新的属性,$old 是 groupStack 数组中最后一个值,以前存进去的本来就有。
首先判断属性中是否存在 domain 这个属性。如果存在,$old 数据中删除这个属性。但是后面会在最后一步把 new 中的 domain 属性合并。相当于重新更新了这个 domain。
2. 然后调用了四个方法分别比较新老数据中 as, namespace, prefix, where
这四个属性,最后使用 array_merge 把他们合并成新的数组。
我们依次来看:
2.1 formatAs()
// 别名的合并这里是前后拼接处理。
protected static function formatAs($new, $old)
{
if (isset($old['as'])) {
$new['as'] = $old['as'].($new['as'] ?? '');
}
return $new;
}
这个很简单,如果 $old
中存在 as 字段的数据,就把 as 字段的数据和 $new
中的 as 字段的数据前后拼接起来返回。
总结一下:这个例子中,如果嵌套了 group,这个 as 就应该是
account.sub.
Route::group(['prefix'=>'accounts','as'=>'account.'], function(){ Route::group(['prefix'=>'accounts','as'=>'sub.'], function(){ Route::get('connect', 'AccountController@connect')->name('connect'); }); });
2.2 formatNamespace()
//namespace 的合并通常就是字符串合并
protected static function formatNamespace($new, $old)
{
if (isset($new['namespace'])) {
return isset($old['namespace']) && strpos($new['namespace'], '\\') !== 0
? trim($old['namespace'], '\\').'\\'.trim($new['namespace'], '\\')
: trim($new['namespace'], '\\');
}
return $old['namespace'] ?? null;
}
1. 如果 $new
中没有 namespace 这个字段(就是 group 方法没有配置这个字段),就使用 $old
的 namespace 数据返回。
2. 否则,先判断,如果 $old
中有 namespace 这个值,并且 $new
中的 namespace 值不只是一个'\'
那就把 $old
中的 namespace 和 $new
中 namesapce 以 '\'
前后拼接起来。
2.3 formatPrefix
// 前缀的合并也类似
protected static function formatPrefix($new, $old)
{
$old = $old['prefix'] ?? null;
return isset($new['prefix']) ? trim($old, '/').'/'.trim($new['prefix'], '/') : $old;
}
也很简单,
如果 $new
中有配置 prefix,就把他和 $old
中的数据以'\'
间隔,拼接起来。如果没有直接使用 $old
的 prefix 数据。
2.4 formatWhere
where 属性用来对 group 中的路由路径,以正则表达式的方式进行配置时的设置。
protected static function formatWhere($new, $old)
{
return array_merge(
$old['where'] ?? [],
$new['where'] ?? []
);
}
这里是直接把这两个 where 规则合并为一个数组。变成规则组,很好理解,因为正则表达式不能用字符串合并嘛。
$old
的 where 可能针对的是所有 group,或者准确的说是当前 group 的上一层 group 的正则表达式限制。new 中的 where 针对的是当前 group 的正则表达式限制。
3. 完成第二步所有的判断组合后,到了这一步
return array_merge_recursive(Arr::except(
$old, ['namespace', 'prefix', 'where', 'as']
), $new);
array_merge 会对键名进行覆盖,而 array_merge_recursive 会把健名相同的合成为一个新数组。
这样就很好理解了。
这里首先调用了:Arr::except
用来清除 $old
前面我们已经处理过的字段。然后再和 $new
合并。(except
这个方法属于 Arr 类,这个类是对数组处理的工具类,有机会再讲。)
简单说就是,
$old
中没有处理过的字段也把他合并到$new
数组中。
总结下好了到这里,现在这个
$new
就是我们合并好了的数组,然后放在 groupStack 数组的尾部,对应了前一节 3.2.1 的内容了。
这就是整个 group 方法中属性合并的逻辑。基本解释了:如果当前 group 还有父 group 的属性 attributes 的情况下,group 方法是如何拼接父 group 中的规则的。
最后强调下 group 属性的这个合并机制是为了给后面加载路由对象使用的。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: