写给thinkphp开发者的laravel系列教程(六)模型

走过了路由;
翻过了控制器;
这就到了模型了;

laravel的数据库部分有一个很大的优点是使用了全球最先进的Eloquent ORM;
她让数据库的操作变的简单安全且无懈可击;
laravel的数据库部分有一个很大的缺点是使用了全球最先进的Eloquent ORM;
她让数据库的操作变的缓慢笨重且无药可救;

laravel 虽然也有一些东西被人诟病;
比如说路由;但是人家好歹可以缓存啊;
Eloquent ORM 你缓存一个看看;
吐槽归吐槽;
Eloquent ORM 作为 laravel 中的一个亮点部分;
也是耗费了 Taylor 相当大精力和时间的成果;
用起来真的相当的强大;

拧干了水分;
咱下面开始讲干货;
首先是连接数据库;
默认是 mysql ;
直接修改根目录下的.env文件中的 DB_HOST、DB_PORT、DB_DATABASE、DB_USERNAME、DB_PASSWORD;
按照 thinkphp 经验;
接着就是创建数据表操作就行了;
但是 laravel 不;
在使用 laravel 的时候我们不能直接操作数据库创建表;
而是要通过数据库迁移 Migrations ;

简单说下迁移;
团队合作中;
咱必须是要使用版本控制的;
不然那配合起来简直惨不忍睹;
比如说 git 可以记录团队成员每次对项目代码的改动;
但是开发的时候咱都知道;
增加或者修改数据表是必不可少的;
我们对表的编辑操作如何同步到其他团队成员的环境中;
或者说如何同步更新到外网的生产环境中是个难题;
以往的时候;
童鞋们可能是每次修改表的时候都记录下;
然后把操作的sql发到团队;
团队成员执行sql以实现结构的更新;
但是这个很容易遗漏造成各种问题;
数据库迁移要解决的就是这个问题;
他让数据库的操作像有git一样可以保留操作记录;

从 thinkphp 转过来的童鞋们;
对数据库的第一个改观就是必须让自己养成使用迁移的习惯;
迁移也是挺简单的;
看着开发文档再参考 database/migrations 目录下自带的 user 表迁移文件;
很容易就上手了;
创建迁移文件也不需要手动创建文件;
laravel 已经很贴心的为我们准备好了命令行;

php artisan make:migration create_表名的复数形式_table

需要强调的就是上面命令中文部分;
laravel 表默认都是以单词的复数形式命名;
还有就是表最好都加上 created_at 、 updated_at;
如果需要软删除加上deleted_at;
分别用于记录此条数据创建、修改、删除的时间;
运行迁移等操作开发文档写的很详细;
这里不赘述;

成功的通过表迁移创建出了一个表后;
咱要操作这张表了;
这里以 articles 表为示例继续;
thinkphp 我们知道可以通过M方法和D方法来实现对表的操作;
laravel 也分别有类似的两种方式;
第一种是实例化DB类传入表名来操作;
thinkphp 中是 M 方法;
laravel 对应的则是 DB facade;

M('article');  // thinkphp
DB::table('articles'); // laravel

而且也都是可以使用连贯操作的;
我们来对比着实现一个比较常用的完整点的查询;

M('articles')
    ->field('id, title, user_id')
    ->where('id < 100')
    ->group('title')    
    ->order('id desc')
    ->having('id > 5')
    ->limit(10)
    ->select();
    // ->count();
    
DB('articles')
    ->select('id', 'title', 'user_id')
    ->where('user_id', 1)
    ->groupBy('title')
    ->orderBy('id', 'desc')
    ->having('id', '>', 5)
    ->limit(10)
    ->get();
    // ->count();

1.先说方法名;
去掉相同的;
where、having、limit、count这几个方法名在两个框架中都是完全一样的;
再去掉只是在后面加个 By 的 orderBy 和 groupBy;
最后我们只需要记住的 限制取出数据的字段;
thinkphp 用的是 field();
laravel 用的是 select();
表示取出数据的方法;
thinkphp 用的是 select();
laravel 用的是 get();
2.接着再来搞定参数;
thinkphp 都是直接把 sql 字符串作为一个参传入数;
laravel 则把 sql 拆分成多个参数;
比如就参考上面代码的 where 或者 having;
比较复杂的则是 where ;
thinkphp 中是直接向 where 传数组;
比如说在 thinkphp 中实现 in 是这样写的;

M('articles')
    ->where(['id' => ['gt', 20], 'user_id' => ['in', [1, 2, 3]]])
    ->select();

laravel 则是多次调用 where;
使用语义化的 where;

DB('articles')
    ->where('id', '>', 20)
    ->whereIn('user_id', [1, 2, 3])
    ->get();

还有 whereNotIn、whereBetween 等等同理;

3.最后来说下查询获取得到的值;
thinkphp 得到的是一个数组;
laravel 得到的则是一个 Collection 对象;
不过可以像 thinkphp 一样循环操作;
不了解 Collection 的先阅读开发文档中的 Collection 集合部分;
刚开始的时候如果实在不习惯 Collection ;
可以调用 ->toArray() 方法把集合转成数组;
这样就跟 thinkphp 获取到的值完全一样了;
不过;建议使用 Collection 集合;
相信我慢慢习惯了你会爱上使用 Collection 的;

直接操作表的方式咱讲完了;
那么下面就是重点要讲的模型了;
和在 thinkphp 中的观点一致;
为了方便复用代码及符合 MVC 模式;
我都是建议使用模型的而不要直接使用M方法;
laravel 中我同样建议使用模型而不直接使用DB;
上文中我讲过表的命名是使用单词的复数形式;
而模型文件的命名则是使用单词的单数形式;
对于有下划线的表名需要写成驼峰形式;
比如说 article_tags 表的模型文件名是 ArticleTag;
依然不需要手动去创建模型文件;
laravel double次的很贴心的为我们准备好了命令行;

php artisan make:model Article

运行命令的话;
你会发现这个文件是建在跟目录下的 app 目录下的;
如果很多表那么模型都默认生成在这个目录下;
作为一个处女座的强迫症;
我非常之不喜欢这种不整齐不统一不按等级目录存放的方式;
同时参考了大量的 laravel 应用;
最后我决定把模型文件放在 app/Models 目录下;
我建议童鞋们也这样来设计模型的目录;
否则;当创建了大量的模型文件后;app 目录下简直无法直视;
命令行也是支持目录的;
上面的命令行就可以改为:

php artisan make:model Models/Article

既然都说建议使用模型了;
那不是每次都要先创建迁移文件再创建模型文件;
虽然是通过命令行但是需要敲两条命令也挺烦;
没错;
laravel triple 次的很贴心的为我们准备好了命令行;

php artisan make:model Models/Article -m

这样在创建模型的命令后面加个 -m
就可以同时创建迁移文件和模型文件;

模型创建好了;
在 thinkphp 中的话;
我们就要开始写自动验证和自动完成了;
画个简(chou)单(lou)的图来便于理解吧;
thinkphp 中一个请求先是到达控制器;
然后在控制器中调用的模型;
模型会先验证数据是否符合要求;
如果符合要求;则执行数据库的增加或修改操作;

laravel 则把验证这部分单独拿出来了;
而且放在了控制器前面;

关于验证部分更详细的参考开发文档吧也是一看就懂;
自动验证我们也就知道在 laravel 中怎么实现了;

自动完成在 laravel 中有两种实现方式;
第一种是比较规则的;
比如说 articles 表中有个 tag_id 字段是记录这篇文章属于哪个标签的;
因为一篇文章可能有多个标签;
那么 tag_id 字段是可以存多个 id 的;
又因为数据库没法直接存个php的数组;
所以我们可以把多个 id 通过json_encode函数转成json存到数据库;
获取数据的时候;再通过 json_decode转成php数组;
这种场景可以直接使用属性类型转换;
在模型文件中定义 casts

/**
 * 属性类型
 *
 * @var array
 */
protected $casts = [
    'tag_id' => 'array',
];

更多定义的属性参考开发文档的存储器部分;
当然如果更复杂的;
我们可以自定义访问器和存储器;
下面手动定义一个访问器和存储器实现属性类型的功能;
命名的规则就是get/set字段名Attribute;

    /**
     * 存入数据库的时候;把数组转成 json
     * @param  string  $value
     * @return void
     */
    public function setTagIdAttribute($value)
    {
        $this->attributes['tag_id'] = json_encode($value);
    }

    /**
     * 获取数据时把json转成php数组
     *
     * @param  string  $value
     * @return string
     */
    public function getTagIdAttribute($value)
    {
        return json_decode($value, true);
    }

其他的类似;参考开发文档很容易就能懂;

thinkphp D函数可以调用的方法和 M函数可以调用的方法一样;
同理;laravel 中模型可以调用的方法和DB也是一样的;
模型中定义自己的方法也是 thinkphp 相同;
我们这里假设在模型中定义了一个 getArticleList 方法用来获取文章列表;

上篇文章我们简单讲了控制器;
在 thinkphp 的控制器 index 方法中调用 getArticleList 是这个样子的;

/**
 * 控制器中的index方法
 */
public function index(){
    D('Articles')->getArticleList();
}

laravel 控制器的方法是可以直接传模型的;
这涉及到一个概念叫 依赖注入;
不懂是什么东西的先搜搜补下基础;
用的时候就是这个样子;
需要先 use App\Models\Article;;
然后如下;

/**
 * 控制器中的index方法
 */
public function index(Article $articleModel){
   $articleModel->getArticleList();
}

作为一个对比学习的系列文章;
我不打算深入讲解;
写了几个小时;
到这可以告一段落了;
买个回城卷轴回被窝了;

白俊遥博客
请先登录后发表评论
  • latest comments
  • 总共24条评论
白俊遥博客

:老哥,你这代码的显示好用,在哪能学习下

2020-06-19 18:50:54 回复

白俊遥博客

天青色等烟雨 :白大师,头部“use DB;” 中的DB文件怎么写,有例子吗

2018-04-07 21:52:17 回复

白俊遥博客

M. :DB 是laravel框架定义好的,  你也可以把自己想要的都去定义. 白俊遥博客

2018-07-12 15:47:08 回复

白俊遥博客

J 白俊遥博客

2018-02-09 18:42:19 回复

白俊遥博客

:d11608787c7da4d0db7bc0fad29a73ca很好的呦

2018-01-18 16:41:34 回复

白俊遥博客

:64ca71169e9079d17ef0b3ab965f97af很好的呦

2018-01-18 16:40:13 回复

白俊遥博客

YOU :数据库操作需要在控制器头部加上  use DB;,否则会报错,送给小白的

2018-01-18 15:07:46 回复

白俊遥博客

﹎ゞ很√想迩 白俊遥博客

2017-12-17 21:43:30 回复

白俊遥博客

孤城浪子 :我觉得你可以直接录一套laravel实战教程卖钱了...

2017-09-04 11:06:15 回复

白俊遥博客 白俊遥博客

云淡风晴 :免费拿去就是;

2017-09-09 00:39:01 回复

白俊遥博客

蝌蚪 :大佬,最近小弟一直在学习你的项目,碰到了一个问题,common模块里的自定义函数build_count_rand(),其中的rand_string(),是个什么意思呢,网上没有找到资料,一直没看太懂....

2017-09-01 18:45:15 回复

白俊遥博客 白俊遥博客

云淡风晴 :生成随机字符串;

2017-09-09 00:40:47 回复

白俊遥博客

那些花儿 :asdsa

2017-08-26 20:28:48 回复

白俊遥博客

蓝蓝的天空 :大神,关于laravel博客的一些问题,希望能够帮我解答一下,加我QQ: 784911193

2017-08-24 13:58:17 回复

白俊遥博客

┅ジ 小猪仔 :请先登录后回复评论

2017-08-25 13:57:50 回复

白俊遥博客

爱便流通于世 :最近研究了laravel 中 cors 有解决的机制吗。白哥。

2017-08-24 09:48:21 回复

白俊遥博客

爱便流通于世 :研究thinkphp5的跨域

2017-08-24 15:43:58 回复

白俊遥博客

PHP部门 :写的不错,但是太短啦!继续加油啊!

2017-08-23 13:27:21 回复

白俊遥博客

一个笨小伙 :这个数据库的迁移什么时候需要用到?

2017-08-23 09:51:41 回复

白俊遥博客 白俊遥博客

云淡风晴 :你想改数据表的时候;

2017-09-09 00:42:26 回复

白俊遥博客

李景lizole :咱...咱...咱...咱...咱...咱...咱...咱...咱...咱......

2017-08-21 16:18:59 回复

白俊遥博客

灵魂摆渡 :不错,学习了

2017-08-21 09:26:22 回复

白俊遥博客

Tara_CK :学习了

2017-08-21 09:03:11 回复

白俊遥博客

那些花儿 :..

2017-08-26 20:29:09 回复