股票场内基金交易,没时间盯盘?
文章更新与代码重用
前言
上一节对表单的非空验证并提示做了一个讲解。本节的主要部分是文章的更新和代码的重构。代码的重构主要体现在视图层上的重构,比较简单。
说明
开发环境:windows 7
laravel版本: 5+
IDE: phpstorm
RESTful 风格的默认路由
了解RESTful请参看wiki这里
routes.php是我们的“路由”的配置文件,这里配置了所有我们指定的合理的路由。不过,Larave 框架其实给我们已经写了很多默认的RESTful风格的路由,怎么能知道这些默认的路由呢?
打开命令行,输入php artisan route:list,可见如下控制台输出:
1 2 3 4 5 6 7 8 9 10 |
+--------+----------+-----------------+------+------------------------------------------------+------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+-----------------+------+------------------------------------------------+------------+ | | GET|HEAD | / | | Closure | web | | | GET|HEAD | articles | | App\Http\Controllers\ArticlesController@index | web | | | POST | articles | | App\Http\Controllers\ArticlesController@store | web | | | GET|HEAD | articles/create | | App\Http\Controllers\ArticlesController@create | web | | | GET|HEAD | articles/{id} | | App\Http\Controllers\ArticlesController@show | web | +--------+----------+-----------------+------+------------------------------------------------+------------+ |
可以看到这是我们之前所写的路由,打开app/Http/routes.php,原先的路由如下所示:
1 2 3 4 5 6 7 8 9 10 |
Route::group(['middleware' => ['web']], function () { Route::get('/', function () { return view('welcome'); }); Route::get('articles', 'ArticlesController@index'); Route::get('articles/create', 'ArticlesController@create'); Route::get('articles/{id}', 'ArticlesController@show'); Route::post('articles', 'ArticlesController@store'); ); |
现在我们把所有的路由都注释掉,并修改成下面这样:
1 2 3 4 5 6 7 |
Route::group(['middleware' => ['web']], function () { Route::get('/', function () { return view('welcome'); }); Route::resource('articles','ArticlesController'); ); |
此时,再在控制台输入:php artisan route:list,可以在控制台看到如下输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
+--------+-----------+--------------------------+------------------+-------------------------------------------------+--------- ---+ | | GET|HEAD | / | | Closure | web | | | GET|HEAD | articles | articles.index | App\Http\Controllers\ArticlesController@index | web | | | POST | articles | articles.store | App\Http\Controllers\ArticlesController@store | web | | | GET|HEAD | articles/create | articles.create | App\Http\Controllers\ArticlesController@create | web | | | GET|HEAD | articles/{articles} | articles.show | App\Http\Controllers\ArticlesController@show | web | | | PUT|PATCH | articles/{articles} | articles.update | App\Http\Controllers\ArticlesController@update | web | | | DELETE | articles/{articles} | articles.destroy | App\Http\Controllers\ArticlesController@destroy | web | | | GET|HEAD | articles/{articles}/edit | articles.edit | App\Http\Controllers\ArticlesController@edit | web | +--------+-----------+--------------------------+------------------+-------------------------------------------------+--------- ---+ |
把我们写的路由都注释掉按理说再输入php artisan route:list是没有路由的,然后我们把路由改成Route::resource(‘Articles’,’ArticlesController’);后,再输入php artisan route:list又能显示出之前的那些路由,这可以说明Route::resource(‘Articles’,’ArticlesController’);可以代替我们之前写的那几条路由。
这是 Laravel 框架的内部的机制,提前为开发者想到这些常用的RESTful风格的路由。
更新文章
文章发布后有时需要修改,所以这一节要实现对文章的更新。
创建edit方法
既然默认的路由里已经有articles/{articles}/edit这一条路由了,这条路由的意思就是当访问localhost/articles/test/edit时候,会对名为test的文章进行编辑,即访问ArticlesController.php里的edit方法。
那么我们到ArticlesController.php里写一个edit方法。
打开app/Http/Controllers/ArticlesController.php,添加一个edit方法如下:
1 2 3 4 5 |
public function edit($id){ $article = Article::findOrFail($id); return view('articles.edit',compact('article')); } |
这个edit方法的意图很明显,首先我要通过id获取到该文章的内容(包括标题、文章题、发表时间),然后将该内容返回给articles目录的edit.blade.php视图。
所以创建一个新的视图吧。
创建edit.blade.php视图
到resources/views/articles/目录下创建一个edit.blade.php文件。
因为编辑文章需要有一个新的视图来承接原文章的内容,那么这个视图跟文章创建的视图很像——标题、内容、发表时间——囊括在一个Form表单中,然后更新。
复制create.blade.php的内容到edit.blade.php中,并修改一些地方:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
@extends('master') @section('content') <h1>Edit Article</h1> <hr> {!! Form::model($article,['method'=>'PATCH','action'=>['ArticlesController@update',$article->id]]) !!} <div class="form-group"> {!! Form::label('title','Title:') !!} {!! Form::text('title',null,['class'=>'form-control']) !!} {!! Form::label('body','Body:') !!} {!! Form::textarea('body',null,['class'=>'form-control']) !!} {!! Form::label('publish_at','Publish On:') !!} {!! Form::date('published_at',Carbon\Carbon::now(),['class'=>'form-control']) !!} {!! Form::submit('Add Article',['class'=>'btn btn-primary form-control']) !!} </div> {!! Form::close()!!} @if ($errors->any()) <ul class="alert alert-danger"> @foreach($errors->all() as $error) <li> {{$error}} </li> @endforeach </ul> @endif @stop |
首先,把大标题改成“Edit Article”(之前是“Create Article”),这无需解释。
然后把Form::open()改成Form::model($article,[‘method’=>’PATCH’,’action’=>[‘ArticlesController@update’,$article->id]])
原因在于,这次我们需要将原对应内容显示到对应的表单中——标题显示到文章的form中,内容显示到内容的form中,发表时间显示到发表时间的form中。之前我们的edit方法已经获取到了原文章的内容,并封装在了名为$article的变量中,并传递到了edit.blade.php,所以这里我们只需要在model()里面引用$article变量,laravel 就会自动帮我们对应这些原来的内容。
这里我们之所以用“PATCH”方法是因为,PATCH是一个局部更新的HTTP协议动词,区别于“PUT”和“POST”,我们是要更新,而不是替换(有点晕,慢慢理解)。
动作指向是ArticlesController的update方法,并且将$article变量的id传递给update方法。
创建update方法
打开ArticlesController.php,创建update方法:
1 2 3 4 5 6 |
public function update($id,Request $request){ $article=Article::findOrFail($id); $article->update($request->all()); return redirect('articles'); } |
这个方法的意图也比较简单,首先看形参,一个$id一个$request,都是接收来自上文edit.blade.php的form表单的数据。你可能会问它怎么知道$id就是上文传递的id?这些问题laravel 都替你想到了,所以不管形参的顺序如何,它都能判断到id,有一个机制叫method injection,感兴趣的可以参看一下。
这个过程中,可能被修改的内容有三处——标题、内容、时间,唯独不变的就是id。所以id依然是从edit方法传递给edit.blade.php的文章的id,但是修改后的内容都被封装在了$request里传递给了update()方法。
到了这个update方法中,根据id先找到文章,然后通过update方法更新原文章(update($request->all())),然后再跳转至localhost/articles/,即可看到更新后的文章里表。
然后开启服务器,可以尝试通过访问localhost:8888/articles/1/edit来修改文章了。
一些问题
虽然完成了修改,不过还有两个问题需要解决。
在更新文章页面中做提示
之前我们在创建文章的时候,表单都不许为空,而且会有提示还记得吧。但是在edit.blade.php中更新文章的时候,没有提示,而且空白也可以提交(你可以试试)。
下面我们改变这一状况。
这些约束还记得是怎么创建的吗,没错,在app/Http/Requests/CreateArticleRequest.php中。
但是这个是给create.blade.php也就是创建文章用的,至少名字上看是这样的,这样不好听。
我们把它改成ArticleRequest.php,这样至少看起来更有好一点,大家都可以用。然后进入ArticleRequest.php中,把类名也同样修改成ArticleRequest,不然会报错找不到ArticleRequest!这里修改完成后,进入ArticlesController.php。
把store()方法和update()方法的形参Request都改成ArticleRequest,最后,把最前面的引用也修改一下,修改成use App\Http\Requests\ArticleRequest。
如此这样,访问localhost:8888/articles/1/edit,留空表单验证是否有提示。
表单代码冗余
在create.blade.php和edit.blade.php中,我们都有相同的表单结构和报错提示,这些冗余的代码其实可以重构一下,写到一个文件中,然后引用一下就好。
报错提示代码重构
比如create.blade.php和edit.blade.php中的这些提示:
1 2 3 4 5 6 7 8 9 10 |
@if ($errors->any()) <ul class="alert alert-danger"> @foreach($errors->all() as $error) <li> {{$error}} </li> @endforeach </ul> @endif |
完全可以写到resources/views/errors这个文件夹下,专门用于存放错误的文件夹。我们在此创建一个名为list.blade.php的文件,将上面的代码复制进来。
然后分别将create.blade.php和edit.blade.php中上面的代码部分替换成:
1 2 |
@include('errors.list'); |
效果是一样的。
表单代码重构
在create.blade.php和edit.blade.php中,他们的表单除了第一行和按钮文字不同外,其他都相同。
所以我们给表单掏空,在resources/views/articles文件夹下创建form.blade.php,并且代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div class="form-group"> {!! Form::label('title','Title:') !!} {!! Form::text('title',null,['class'=>'form-control']) !!} {!! Form::label('body','Body:') !!} {!! Form::textarea('body',null,['class'=>'form-control']) !!} {!! Form::label('publish_at','Publish On:') !!} {!! Form::date('published_at',Carbon\Carbon::now(),['class'=>'form-control']) !!} {!! Form::submit('Add Article',['class'=>'btn btn-primary form-control']) !!} </div> |
按钮怎么办,一个是add article,一个是update article。
首先把form.blade.php修改如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div class="form-group"> {!! Form::label('title','Title:') !!} {!! Form::text('title',null,['class'=>'form-control']) !!} {!! Form::label('body','Body:') !!} {!! Form::textarea('body',null,['class'=>'form-control']) !!} {!! Form::label('publish_at','Publish On:') !!} {!! Form::date('published_at',Carbon\Carbon::now(),['class'=>'form-control']) !!} {!! Form::submit($submitButtonText,['class'=>'btn btn-primary form-control']) !!} </div> |
没错,将“Add Article”变成一个变量。
然后。
在create.blade.php中,这样来:
1 2 3 4 5 6 7 8 9 10 11 |
@extends('master') @section('content') <h1>Create Article</h1> <hr> {!! Form::open(['url'=>'articles']) !!} @include('articles.form',['submitButtonText'=>'Add Article']) {!! Form::close()!!} @include('errors.list') @stop |
看到了吗,在include(‘articles.form’)的同时传递一个名为submitButtonText的值为“Add Article”。
同理,在edit.blade.php中:
1 2 3 4 5 6 7 8 9 10 11 |
@extends('master') @section('content') <h1>Edit Article</h1> <hr> {!! Form::model($article,['method'=>'PATCH','action'=>['ArticlesController@update',$article->id]]) !!} @include('articles.form',['submitButtonText'=>'Update Article']) {!! Form::close()!!} @include('errors.list') @stop |
给submitButtonText传递“Update Article”。
这样一来就可以既灵活又简洁的解决了代码冗余的问题,也使得form表单的代码得到了重用。
总结
本节解决了如下几个问题:
- 路由的简洁替换
- 文章的更新
- 代码的重用
本节的代码重用的地方较多,这也是作为开发者的我们需要注意的一个重要的环节。
代码的重用既缩小工作量,也可以使得代码更加简洁。
作为开发者应该时时review代码,做代码重构。
想获得去掉 5 元限制的证券账户吗?

如果您想去掉最低交易佣金 5 元限制,使用微信扫描左边小程序二维码,访问微信小程序「优财助手」,点击底部菜单「福利」,阅读文章「通过优财开证券账户无最低交易佣金 5 元限制」,按照文章步骤操作即可获得免 5 元证券账户,股票基金交易手续费率万 2.5。
请注意,一定要按照文章描述严格操作,如错误开户是无法获得免 5 元证券账户的。