模型Eloquent ORM的使用(二)

对于模型的探索我们还将继续。上篇文章中,只是简单地通过模型操作了一下数据库,并且学习了一下关联操作的知识。今天,我们继续学习模型中别的一些好玩的东西,不过,我们不会继续深入地学习模型中别的相关技巧。因为这些东西,都已经写在了官方文档中,而对于这个系列的文章来说,入个门,然后搞清楚原理才是最重要的,对于怎么使用这个事,大家自己好好研究就好了。而且,关于使用的内容,网上也有很多文章以及视频教程了,我也就不走别人的老路咯。

集合操作

其实这个集合操作并不是模型特有的,还记得在 查询构造器 中,我们查询列表的时候,总会在最后加一个 toArray() 吗?这个 toArray() 并不是 Builder 中的方法,如果不加这个 toArray() ,返回的是什么大家有没有注意过?

Route::get('model/test/collection', function () {$where = [];if(request()->name){$where[] = ['name', 'like', '%' . request()->name . '%'];}if(request()->sex){$where[] = ['sex', '=', request()->sex];}$list = \App\Models\MTest::where($where)->orderBy('id', 'desc')->limit(10)->offset(0)->get();dd($list);// Illuminate\Database\Eloquent\Collection Object
// (
//     [items:protected] => Array
//         (
//             [0] => App\Models\MTest Object
//                 (
//                     [table:protected] => m_test
//                     [timestamps] =>
//                     [connection:protected] => mysql
//                     [primaryKey:protected] => id
//                     [keyType:protected] => int
//                     [incrementing] => 1
//                     [with:protected] => Array
//                         (
//                         )//                     [withCount:protected] => Array
//                         (
//                         )//                     [perPage:protected] => 15
//                     [exists] => 1
//                     [wasRecentlyCreated] =>
//                     [attributes:protected] => Array
//                         (
//                             [id] => 20
//                             [name] => Jim
//                             [sex] => 1
//                         )//                     [original:protected] => Array
//                         (
//                             [id] => 20
//                             [name] => Jim
//                             [sex] => 1
//                         )
//         ………………
//         ………………
//         ………………});

打印出来,我们会发现,它返回的是一个 laravel/framework/src/Illuminate/Database/Eloquent/Collection.php 对象,然后这个对象里面有个 items 属性,是一个数组。这个对象就是我们的模型组件中的集合对象,它包含很多集合操作的方法,如果以最简单的角度理解的话,其实它就是帮我们封装了很多数组操作函数。

这个集合对象有什么作用呢?其实很明显了,它提供了各种数组操作函数,就是有很多数组操作我们可以以对象的形式提供。比如说我们可以使用类似于 array_map() 的函数把集合中的对象全部转换成数组,还可以用一个类似于 array_column() 的函数只获取数据中的两个字段组成键值对形式的数据。

$list = \App\Models\MTest::where($where)->orderBy('id', 'desc')->limit(10)->offset(0)->get()->pluck('name', 'id')->toArray();
print_r($list);
//    Array
//    (
//        [20] => Jim
//        [19] => Mary
//        [18] => Susan
//        [17] => Tom
//        [16] => Peter
//        [15] => Jim
//        [14] => Mary
//        [13] => Susan
//        [12] => Tom
//        [11] => Peter
//    )$list = \App\Models\MTest::where($where)->orderBy('id', 'desc')->limit(10)->offset(0)->get()->map(function($item){ return $item->attributesToArray();})->toArray();
print_r($list);
//    Array
//    (
//        [0] => Array
//        (
//            [id] => 20
//            [name] => Jim
//            [sex] => 1
//        )
//        [1] => Array
//        (
//            [id] => 19
//            [name] => Mary
//            [sex] => 2
//        )
//         ………………
//         ………………
//         ………………
//    )

上面的 plucks() 就是类似于 array_column() 的函数操作,用于获取数组元素指定的列值,这样生成的列表对于一些下拉框的接口非常友好。而另外一个 map() 函数就不用多说了,之前我们说过,Laravel 的 PDO 在默认查询构造器的情况下,走的是 PDO::FETCH_OBJ ,获得的集合结果中的每个数据都是一个 stdClass 对象,而在 Model 下,走的则是 PDO::FETCH_CLASS ,也就是会和我们指定的模型类关联上,获得的结果都是一个 App\Models\MTest Object 对象。而我们在日常的操作中,其实最习惯的是使用数组那种形式的操作,除开我们后面会讲的直接从配置入手来修改 PDO FETCH 属性之外,我们还可以用上面这个 map() 函数配合模型对象的 attributesToArray() 方法来将模型对象转换成数组格式。

当然,这个集合类相关的操作函数还有很多,这里我们只是演示了两个,具体的内容大家自行查阅一下官方手册。而源码呢?我也只给出具体的文件,大家自己去看看,里面的数组各种操作功能都非常经典。laravel/framework/src/Illuminate/Collections/Collection.php 是集合类,里面的方法大部分都调用的是 laravel/framework/src/Illuminate/Collections/Arr.php 里面的方法。

与路由绑定

对于一些获取单个信息的操作来说,模型是可以直接绑定到路由上的,比如下面这样:

Route::get('model/test/bindroute/{mTest}', function(\App\Models\MTest $mTest){dump($mTest);dump($mTest->name);
});

通过在回调函数中注入模型对象,就可以实现路由与模型的绑定。这里路由的 mTest 参数实际上就是我们查询数据的主键 ID ,然后模型就会自动为我们查询相应的数据并注入到 $mTest 参数中。除了直接绑定路由外,通过控制器实现也是一样的,我们只需要将回调函数变成指定的控制器方法即可。

Route::get('model/test/bindroute/controller/{mTest}', [\App\Http\Controllers\MTestController::class, 'show']);class MTestController extends Controller
{public function show(MTest $mTest){dump($mTest);dump($mTest->name);}
}

快速序列化

对于模型的序列化来说,有两种形式的序列化,一是序列化为数组,二是序列化为 JSON 格式字符串。我们先看看第一种。

Route::get('model/test/ser/array', function(){$mTest = \App\Models\MTest::find(1);dump($mTest->toArray());dump($mTest->attributesToArray());
});

这个其实没有什么多说的,因为 toArray() 和 attributesToArray() 都是我们之前用过的,但是要注意的是,它们两个是不同的概念。toArray() 方法是一个递归方法,它会将所有的属性和关联(包括关联的关联)都转化成数组。而 attributesToArray() 只会将当前模型的属性转化为数组。

对于 JSON 格式,其实也只是调用一个 toJson() 方法就可以方便地实现。

Route::get('model/test/ser/json', function(){$mTest = \App\Models\MTest::find(1);dump($mTest->toJson());dump($mTest->toJson(JSON_PRETTY_PRINT));
});

toJson() 所接收到的参数就是我们日常可以使用的 JSON 系列常量。这个没有什么多说的,大家可以自己尝试一下。

模型调用的是查询构造器?

之前我们就一直在强调,原生查询 操作封装成 查询构造器 ,然后 查询构造器 进一步面向对象化的封装变成了 ORM 类型的 模型 。这是一个连续递进的关系,之前在 查询构造器 的文章中,我们已经看到了它的底层就是调用的 原生查询 操作。那么这回,我们再来看一下 Model 中的方法,在底层是不是调用的是 查询构造器 。

在所有模型都要继承的 laravel/framework/src/Illuminate/Database/Eloquent/Model.php 类中,我们很快就能发现一个 query() 静态方法。一路向下追踪,你马上就会发现它最后会调用到一个 newBaseQueryBuilder() 方法。

protected function newBaseQueryBuilder()
{return $this->getConnection()->query();
}

这个似乎就已经非常明显了。getConnection() 会返回一个之前讲过的工厂方法创建的 Connection 对象,而 query() 方法则会根据 Connection 创建一个 QueryBuilder 对象。剩下的还需要我们细讲吗?我觉得到这里真的已经非常清晰了。

然后我们来看一下这个 Model 基类中的其它方法,貌似没有发现 get() 、find() 之类的方法呀?这是怎么回事。别急,get() 、find() 不都是在 查询构造器 中的方法嘛。我们来看看 Model 中的 __call() 这个方法。

public function __call($method, $parameters)
{if (in_array($method, ['increment', 'decrement'])) {return $this->$method(...$parameters);}if ($resolver = (static::$relationResolvers[get_class($this)][$method] ?? null)) {return $resolver($this);}return $this->forwardCallTo($this->newQuery(), $method, $parameters);
}

当前类中找不到的方法就会进入 __call() 魔术方法中,在这里,我们看到它调用了 forwardCallTo() 方法,然后传递进去的是一个新的 查询构造器 对象和方法名以及参数。不过这里需要注意的是,模型默认生成的 QueryBuilder 是 llaravel/framework/src/Illuminate/Database/Eloquent/Builder.php 对象,而不是我们之前 查询构造器 中的 laravel/framework/src/Illuminate/Database/Query/Builder.php 对象。但 Eloquent\Builder 的内部持有的一个 $query 属性依然是 Query\Builder 对象,也就是说在底层,它依然是调用的我们熟悉的那个 查询构造器 来进行工作的。但是,这里划重点了,Eloquent\Builder 中有些方法是没有的,比如说 insert()、insertGetId() ,在模型中,使用 save() 就可以代替这两个方法的操作。说白了,直接 $mTest->insert() 是会报错的,不过也有方法解决,只不过那样就完全像是使用一个 查询构造器 了,大家自己找找解决方案哦。

总结

关于模型的内容还有很多,在这里我们就不一一讲解了。相关的源码也都在上面的源码文件路径中都给出了,其它有意思功能的源码大家可以自己尝试去分析一下,毕竟我们也学习了一段时间了,相信很多东西大家自己也能找到了。最主要的还是那句话,看框架真的就是在考验你的基础水平,找不到方法了怎么办?找 __call() 或者 __callStatic() ;找不到属性了怎么办?找 __set()、__get() ;来回调用看着好晕怎么办?Debug工具与编辑器的配置一定要配好,设计模式一定要理解透。相信有了这些,后面的内容你也可以写出来了,期待大家的分享哦!

参考文档:

https://learnku.com/docs/laravel/8.x/eloquent/9406

【Laravel系列4.4】模型Eloquent ORM的使用(二)相关推荐

  1. laravel组件单独加载(2):模型 Eloquent ORM

    模型组件的加入 目前的项目代码是基于上一个文章的,不知道的可以看上一个文章laravel组件单独加载(1):路由 修改composer.json文件加入模型组件 {"require" ...

  2. 1+X web中级 Laravel学习笔记——Eloquent ORM查询、更新、删除、新增

    Eloquent ORM简介 larave1所自带的Eloquent oRM是一个非常优美简洁的ActiveRecord实现,用来实现数据库的操作他的每个数据的表都有对应的模型(model)用于数据表 ...

  3. Laravel Lumen之Eloquent ORM使用速查-基础部分

    使用Eloquent ['eləkwənt] 时,数据库查询构造器的方法对模型类也是也用的,使用上只是省略了DB::table('表名')部分. 在模型中使用protected成员变量$table指定 ...

  4. [转]Laravel 4之Eloquent ORM

    Laravel 4之Eloquent ORM http://dingjiannan.com/2013/laravel-eloquent/ 定义Eloquent模型 模型通常放在app/models目录 ...

  5. 【整理】Laravel中Eloquent ORM 关联关系的操作

    Laravel中Eloquent ORM 关联关系的操作 关联数据 定义关联关系 一对一 <?php class User extends Model{// 获取关联到用户的手机public f ...

  6. 解决laravel框架中Eloquent ORM的save方法无法插入数据的问题

    学习laravel中: 今天在测试使用Eloquent ORM将数据使用 save()方法插入到mysql中时,出现了错误,如图所示: 在网上查阅资料后找到了原因: 使用save方法新增数据: lar ...

  7. Laravel 5.1 文档攻略——Laravel Eloquent ORM最强大也是最难理解的部分:数据关系...

    简介 其实大家都知道,数据表之间都是可以关联的,Eloquent ORM是数据模型操作代替表操作,那么表的关联查询,在Eloquent这里也就是模型间的关联查询,这就是本章的主要内容: Eloquen ...

  8. Laravel之Eloquent ORM

    一.ORM编程思想 1.1 Active Record 设计模式 Active Record 是一种数据访问设计模式,它可以帮助你实现数据对象Object到关系数据库的映射.应用Active Reco ...

  9. Laravel 的 Eloquent ORM学习

    创建模型 首先,创建一个 Eloquent 模型,生成的模型通常放在 app 目录中,但你可以通过 composer.json 随意地将它们放在可被自动加载的地方.所有的 Eloquent 模型都继承 ...

  10. Laravel 系列入门教程(一)【最适合中国人的 Laravel 教程】

    热烈庆祝 Laravel 5.5 LTS 发布! 实际上 Laravel 上一个 LTS 选择 5.1 是非常不明智的,因为 5.2 增加了许许多多优秀的特性.现在好了,大家都用最新的长期支持版本 5 ...

最新文章

  1. Win7下让MSN离开任务栏
  2. ThreadLocal管理Connection
  3. Camera摄像头工作原理
  4. 一图梳理企业数据治理的8项举措
  5. vue放大缩小div_vue 放大缩小 svg 图形(原理类似整个列表更新)
  6. docker build 变量_Docker从入门到掉坑(二):基于Docker构建SpringBoot微服务
  7. 如何判断一个类是无用的类?
  8. Git linux下保存密码方法
  9. Python使用xpath爬取51job
  10. QQ2007密码盗取程序介绍(参考部分网上代码)
  11. synchronized原理
  12. 我们的另一半,最熟悉的陌生人
  13. mysql outer apply_使用 CROSS APPLY 与 OUTER APPLY 连接查询
  14. 透过细节看日本(转)
  15. 输出一个小游戏——三子棋
  16. 【华为OD机试真题 Java】统计射击比赛成绩
  17. python关于列表去重和删除的方法
  18. uniapp绘制分享海报
  19. SEC S3C2410X Test B/D 驱动安装
  20. keil5安装及注册许可

热门文章

  1. dell笔记本插上耳机没有声音_笔记本扬声器没声音,但耳机有声音怎么办
  2. gromacs 安装_GROMACS安装专述
  3. 如何删除数据库中的冗余数据…
  4. 使用SVM模型对京东评价进行情感分析---【大白话版】
  5. 植物大战僵尸最全最新版修改存档
  6. magento 为用户注册增加一个字段
  7. 明清时期华北宗族的发展——以山西洪洞刘氏为例
  8. 原来Mysql索引要这么设计才能起飞
  9. vp230引脚功能_CAN收发器—TJA1040与TJA1050区别
  10. 计算机管理磁盘管理,windows7双磁盘管理图文教程