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 协议》,转载必须注明作者和本文链接
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!