Blogger Information
Blog 57
fans 3
comment 0
visits 60362
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
laravel实战-通用后台管理系统-扩展数据库访问类/主键做数组key替代关联查询
岂几岂几
Original
786 people have browsed it

laravel实战-通用后台管理系统-扩展数据库访问类/主键做数组key替代关联查询

扩展数据库访问类

  • laravel的查询结果, 是对象数组, 一个对象就是一条表记录. 通过扩展数据库访问类, 把对象数组转换成方便使用的二维数组, 一个数组就是一条表记录.

  • 扩展数据库访问类, 可以找到该类, 在里面增加新方法, 但是这样会破坏框架的源码, 框架升级后, 会被覆盖, 不推荐.

  • laravel提供了一个叫 MacroableTraits , 凡是使用了 Macroable 的类, 都可以使用其提供的 macro() 方法来扩展类的功能. 而laravel的数据库访问类 \Illuminate\Database\Query\Builder 使用了 Macroable , 所以可以使用 macro() 方法扩展功能.

  • macro() 方法的调用方式: 调用方法是: [被扩展新方法的laravel内置类]::macro(扩展方法名, 闭包); . 调用 macro() 方法的代码, 应该放在laravel提供的”服务提供者”类中. 具体使用流程:

      1. 判断类具有”可宏扩展”性的方法: 打开类定义文件, 如果它使用了名为 Macraoabletrait , 则这个类就具有了”可宏扩展”性.
      1. 扩展框架内置类的类文件, 创建到 /app/Providers 目录中, 命名方式: XxxServiceProvider.php . 类继承 Illuminate\Support\ServiceProvider 类(好像也可以继承别的类似ServiceProvider类)
      1. XxxServiceProvider 中创建 public function boot() {...} 方法, 调用 [被扩展新方法的laravel内置类]::macro(扩展方法名, 闭包); 方法, 在闭包中编写扩展的方法的逻辑.
      1. /config/app.php 文件中的 providers 数组中注册 XxxServiceProvider 类.
      1. 在代码中用被扩展的类调用扩展方法.
    • 参考资料: 如何利用 macro 方法来扩展 Laravel 的基础类的功能, 扩展包开发-服务提供者

代码:

1-服务提供者类 DBServiceProvider.php

  1. <?php
  2. namespace App\Providers;
  3. use Illuminate\Support\ServiceProvider;
  4. // 门面类 `Illuminate\Support\Facades\DB` 实际的操作类是 `Illuminate\Database\Query\Builder` 类, 它使用了trait: `Macroable` .
  5. use Illuminate\Database\Query\Builder as QueryBuilder;
  6. class DBServiceProvider extends ServiceProvider {
  7. /**
  8. * 必须要有这个方法
  9. */
  10. public function boot() {
  11. /**
  12. * 扩展laravel的DB类,返回二维数组类型的查询结果集
  13. */
  14. QueryBuilder::macro('lists', function() {
  15. // 这里的$this是指向被扩展类(即, Builder类)
  16. $data = $this->get()->toArray();
  17. $lists = [];
  18. foreach($data as $val) {
  19. // 对象强转成数组
  20. $lists[] = (array) $val;
  21. }
  22. return $lists;
  23. });
  24. /**
  25. * 扩展laravel的DB类,获取数组类型的第一条查询结果
  26. */
  27. QueryBuilder::macro('getFirst', function() {
  28. // 这里的$this是指向被扩展类(即, Builder类)
  29. $data = (array) $this->first();
  30. return $data;
  31. });
  32. }
  33. }

2-在 /config/app.php 中的 providers 属性中注册内容提供者类(略).

3-在代码中调用扩展的方法( \Illuminate\Support\Facades\DB 是laravel访问数据库的 \Illuminate\Database\Query\Builder 类的门面类)

  1. <?php
  2. namespace App\Http\Controllers\admins;
  3. use App\Http\Controllers\Controller;
  4. use Illuminate\Support\Facades\DB;
  5. class Admin extends Controller {
  6. public function index() {
  7. // 像使用DB类默认提供的方法一样使用扩展的方法.
  8. $data['admins'] = DB::table('admin')->lists();
  9. // 其他业务逻辑略...
  10. }
  11. }

2. 主键做数组key替代关联查询

  • 大部分数据库表之间的关联, 是把一个表A的主键以外键字段的方式放在另一个表B. 若查询A表时, 查询结果能以记录的主键做数组key, 则可在渲染后表数据时, 以外键为key从A表的结果集数组中获取对应的A表记录.

    • 当A表数据不多时, 使用这样的方法, 可以代替关联查询. 在管理员列表中使用循环中查询管理员的所属用户组的方式可以扔进垃圾桶了.
  • 可以使用上一节介绍的扩展数据库访问类的方法, 再扩展一个 keyval(作为key的字段, 作为值的字段[可选]) 方法, 实现上述需求.

1-在服务提供者实现类中( DBServiceProvider )添加 keyval() 方法

  1. /**
  2. * 扩展laravel的DB类,把查询结果中的一列作为key,另一列作为value; 若没有指定作为value的列名, 则以整个结果集作为value。
  3. */
  4. QueryBuilder::macro('keyval', function($key, $val = null) {
  5. // 查询数组
  6. $data = $this->lists();
  7. // 获取作为key的列
  8. $keyColumn = array_column($data, $key);
  9. // 判断形参$val的值是否存在
  10. if(!empty($val)) {
  11. // $val值存在,则把列名为$val的列作为值。
  12. $valColumn = array_column($data, $val);
  13. if(isset($keyColumn) && isset($valColumn)) {
  14. return array_combine($keyColumn, $valColumn);
  15. }
  16. } else {
  17. // $val不存在,则把结果集作为值
  18. if(isset($keyColumn)) return array_combine($keyColumn, $data);
  19. }
  20. // 不能处理的情况,返回空数组
  21. return [];
  22. });

2-改造查询管理员列表数据控制器方法

  1. <?php
  2. namespace App\Http\Controllers\admins;
  3. use App\Http\Controllers\Controller;
  4. use Illuminate\Support\Facades\DB;
  5. class Admin extends Controller {
  6. public function index() {
  7. $data['admins'] = DB::table('admin')->lists();
  8. /* 当前业务逻辑值需要查出用户组的组名一个字段,所以并不需要查出所有的字段值 */
  9. $groups = DB::table('admin_group')->keyval('gid', 'title');
  10. // 传给视图渲染
  11. $data['groups'] = $groups;
  12. return view('admins/admin/index', $data);
  13. }
  14. }

3-管理员视图文件中渲染时调用(代码片段)

  1. /* 获取用户所属分组的名称 */
  2. <!-- 如果后端的keyval()方法指定了value列名,则使用这个调用取值 -->
  3. <td>{{$groups[$admin['gid']]}}</td>

学习心得

  • 这是管理员管理功能实现中西门老师介绍的编码技巧, 其实不使用这些技巧, 也能实现业务逻辑. 而使用了这些技巧, 一方面可以提高执行效率, 减少服务器压力; 另一方面, 可以使代码更优雅.
Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:总结的很完整, 不错哟
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post