laravel的查询结果, 是对象数组, 一个对象就是一条表记录. 通过扩展数据库访问类, 把对象数组转换成方便使用的二维数组, 一个数组就是一条表记录.
扩展数据库访问类, 可以找到该类, 在里面增加新方法, 但是这样会破坏框架的源码, 框架升级后, 会被覆盖, 不推荐.
laravel提供了一个叫 Macroable
的 Traits
, 凡是使用了 Macroable
的类, 都可以使用其提供的 macro()
方法来扩展类的功能. 而laravel的数据库访问类 \Illuminate\Database\Query\Builder
使用了 Macroable
, 所以可以使用 macro()
方法扩展功能.
macro()
方法的调用方式: 调用方法是: [被扩展新方法的laravel内置类]::macro(扩展方法名, 闭包);
. 调用 macro()
方法的代码, 应该放在laravel提供的”服务提供者”类中. 具体使用流程:
Macraoable
的 trait
, 则这个类就具有了”可宏扩展”性./app/Providers
目录中, 命名方式: XxxServiceProvider.php
. 类继承 Illuminate\Support\ServiceProvider
类(好像也可以继承别的类似ServiceProvider类)XxxServiceProvider
中创建 public function boot() {...}
方法, 调用 [被扩展新方法的laravel内置类]::macro(扩展方法名, 闭包);
方法, 在闭包中编写扩展的方法的逻辑./config/app.php
文件中的 providers
数组中注册 XxxServiceProvider
类.代码:
1-服务提供者类 DBServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
// 门面类 `Illuminate\Support\Facades\DB` 实际的操作类是 `Illuminate\Database\Query\Builder` 类, 它使用了trait: `Macroable` .
use Illuminate\Database\Query\Builder as QueryBuilder;
class DBServiceProvider extends ServiceProvider {
/**
* 必须要有这个方法
*/
public function boot() {
/**
* 扩展laravel的DB类,返回二维数组类型的查询结果集
*/
QueryBuilder::macro('lists', function() {
// 这里的$this是指向被扩展类(即, Builder类)
$data = $this->get()->toArray();
$lists = [];
foreach($data as $val) {
// 对象强转成数组
$lists[] = (array) $val;
}
return $lists;
});
/**
* 扩展laravel的DB类,获取数组类型的第一条查询结果
*/
QueryBuilder::macro('getFirst', function() {
// 这里的$this是指向被扩展类(即, Builder类)
$data = (array) $this->first();
return $data;
});
}
}
2-在 /config/app.php
中的 providers
属性中注册内容提供者类(略).
3-在代码中调用扩展的方法( \Illuminate\Support\Facades\DB
是laravel访问数据库的 \Illuminate\Database\Query\Builder
类的门面类)
<?php
namespace App\Http\Controllers\admins;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
class Admin extends Controller {
public function index() {
// 像使用DB类默认提供的方法一样使用扩展的方法.
$data['admins'] = DB::table('admin')->lists();
// 其他业务逻辑略...
}
}
大部分数据库表之间的关联, 是把一个表A的主键以外键字段的方式放在另一个表B. 若查询A表时, 查询结果能以记录的主键做数组key, 则可在渲染后表数据时, 以外键为key从A表的结果集数组中获取对应的A表记录.
可以使用上一节介绍的扩展数据库访问类的方法, 再扩展一个 keyval(作为key的字段, 作为值的字段[可选])
方法, 实现上述需求.
1-在服务提供者实现类中( DBServiceProvider
)添加 keyval()
方法
/**
* 扩展laravel的DB类,把查询结果中的一列作为key,另一列作为value; 若没有指定作为value的列名, 则以整个结果集作为value。
*/
QueryBuilder::macro('keyval', function($key, $val = null) {
// 查询数组
$data = $this->lists();
// 获取作为key的列
$keyColumn = array_column($data, $key);
// 判断形参$val的值是否存在
if(!empty($val)) {
// $val值存在,则把列名为$val的列作为值。
$valColumn = array_column($data, $val);
if(isset($keyColumn) && isset($valColumn)) {
return array_combine($keyColumn, $valColumn);
}
} else {
// $val不存在,则把结果集作为值
if(isset($keyColumn)) return array_combine($keyColumn, $data);
}
// 不能处理的情况,返回空数组
return [];
});
2-改造查询管理员列表数据控制器方法
<?php
namespace App\Http\Controllers\admins;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
class Admin extends Controller {
public function index() {
$data['admins'] = DB::table('admin')->lists();
/* 当前业务逻辑值需要查出用户组的组名一个字段,所以并不需要查出所有的字段值 */
$groups = DB::table('admin_group')->keyval('gid', 'title');
// 传给视图渲染
$data['groups'] = $groups;
return view('admins/admin/index', $data);
}
}
3-管理员视图文件中渲染时调用(代码片段)
/* 获取用户所属分组的名称 */
<!-- 如果后端的keyval()方法指定了value列名,则使用这个调用取值 -->
<td>{{$groups[$admin['gid']]}}</td>