字面上理解queryScope和setAttribute 分别是 查询范围和设置属性的意思,那到底在laravel中是作何使用的呢?解决什么问题呢?
这里我首先是想向大家简单说说这两个知识点得应用场景是什么,我们在开发的时候,总是希望有一种偷懒的方式,所以考虑以下这两个场景:
1、数据在存入数据库的时候需要进行预先处理,比如考虑一个简单地例子:我们在保存用户的登录密码的时候,都是需要将密码用某种方式加密过后在写入数据库的,我们难道在每一次在提交表单过来之后都对传过来的数据进行一次数据加密么?能不能有一种自动完成对密码入库前就加密的机制呢?这样我们在处理表单的时候就不用关心密码加密的问题了
2、想一想我们在向用户展示的数据是不是基本上都是从数据库取的呢?那么往往我们会有很多的查询语句,在这样的情况之下很多的查询语句可以就会重复,但是在写代码这一行中,一旦出现多个重复,基本上就会有优化方式存在,所以这个时候queryScope就派上用场了
第一步 使用Laravel项目的artisan命令行工具先启动一下项目,执行命令:php artisan serve
D:\software\wamp64\www\laravel5>php artisan serve
看上一节,使用 illuminate/html这个包创建html 时,我们都是将published_at设置为文章创建的日期:
$input['published_at'] = Carbon::now();
然而这并不是我们想要的,我们希望有一种可以控制的方式,比如在表单之中设置文章的发布日期,所以,我们来实现一下:首先将
修改 ArticlesController 控制器的 store 方法。
public function store(Request $request) { Article::create($request->all()); return redirect('/articles'); }
然后将published_at这个字段放到我们的form之中,在create.blade.php中,加入published_at 输入框输入:
{!! Form::label("published_at") !!} {!! Form::input("date","published_at",date("Y-m-d")) !!}<br>
这一段代码加在Intro后面,这里使用了Form::input(),这个方法,因为Form这个类没有类似Form::date()指定date的方法,所以我们使用Form::input()并指定input的类型为date,并使用date('Y-m-d')来指定默认值为文章发布当天,但是我们可以修改,我们来看看我们的页面现在是什么样的:
这里我们可以看到我们拿到了published_at这个字段了。这个时候新添加文章之后,就会在首页看到我们新添加的文章。单是有一个问题,就是该发布时间字段 published_at 在数据库的存储方式,如图所示:默认的 00:00:00,这里的日期设置成的格式并不是理想的模式
如何可以使该字段 正常显示呢?
这个时候我们就可以使用到 setAttribute ,通过对 该model 的 published_at 设置setAttribute 即可 起到 预处理的效果。
修改 app/Article.php 该文件,增加 如下代码(这里还是使用 Carbon处理类):
namespace App; use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; class Article extends Model { // protected $fillable = ['title','content','published_at','intro']; //set + 数据库预处理字段 +Attribute public function setPublishedAtAttribute($date) { $this->attributes['published_at'] = Carbon::createFromFormat('Y-m-d',$date); } }
从新添加一篇文章,这样一来格式是对了,published_at 该字段就变成了年月日 时分秒 2018-07-21 16:59:21 的效果。
上面实现了用published_at实现了文章的发布日期,但是现在的文章展示还是原来的样式,这并不是我们想要的结果,因为我们刚刚设置发表日期为之后的文章,首页也展示出来了,我们得限制一下。
首先我们可以在查询的时候直接实现,比如在ArticleController的index()方法中将查询语句写成这样:
public function index() { $articles = Article::latest()->where('published_at','<=',Carbon::now())->get(); return view('articles.index', compact('articles')); }
我们使用where()直接限制published_at时间小于或等于当前时间的文章才进行显示。
发现在未来时间发布的文章确实隐藏了,这样貌似已经达到了目的,为什么还要引入qeuryScope这个用法呢?这是因为考虑到代码的重用性,比如我们要是多个地方使用到Article::where('published_at','<=',Carbon::now())这个条件限制呢,我们有没有一种方式可以将查询语句写成类似下面这种形式呢?
$articles = Article::latest()->published()->get();
就是直接使用published()这个自定义的方法来代替where('published_at','<=',Carbon::now())呢,这样代码可读性也会更好。
在我们的Article.php中增加下面的方法:
//scope+自定义的方法名字 public function scopePublished($query) { $query->where('published_at','<=',Carbon::now()); }
这里注意一下写法scope+自定义的方法名字,还有就是一如既往的驼峰法。比如我们想使用published()这个方法,就定义为scopePublished($query)。这个时候就可以真正的使用上面说的查询了,在ArticleController的index()方法中:
$articles = Article::latest()->published()->get();
再去看看效果,相信你刷新之后还是一样的。
本文为崔凯原创文章,转载无需和我联系,但请注明来自冷暖自知一抹茶ckhttp://www.cksite.cn