一、背景描述
经常我们在写某一个功能模块时,要用到的功能无非就是增删改查,如果按照基础的实现方式,我们会发现,做一个模块功能时,获取文件列表,需要写一个路由,打开编辑页面,需要一个路由,甚至删除某条数据,仍然需要一个路由,这种重复工作,让人会觉得很难受。而且如果每一个页面或者功能都去写一个路由的话,路由文件也会显得特别冗杂,重复性也很大。
我们希望代码美观且简洁,如果只写一个路由,然后根据请求方式(GET/PUT/POST/DELETE等)或者是否传参来判断访问的是哪个方法,这样一个功能模块,只需要一个路由就可以解决了。刚好,Laravel不愧是美誉盛传的PHP框架,刚好就有这样一个路由机制,Resource。大部分情况下,一个模块只需要在路由文件中定义一个resource路由,就可以实现对整个模块的请求。
下面,我们实操完成一个文章模块。
二、Resouce路由使用步骤
1. 注册资源路由
// 普通注册
Route::resource('article', 'ArticleController');
// 限制指定路由
Route::resource('article', 'ArticleController', ['only' => [
'index', 'show', 'store', 'update', 'destroy'
]]);
注意
(1)我这里是在做后台的文章模块,所以在Controllers下新建了一个Admin文件夹,所以新建后台的文章模块控制器需要加一个文件夹 “ Admin ” 。
(2)当前这个路由文件是一个自定义的admin.php路由文件,直接路由到 “/Controllers/Admin/” 文件夹下的。如何在Laravel中自定义路由文件,参考我的另一篇博文:Laravel5.5添加新路由文件并制定规则。
(3)resource路由包含多个子路由,具体参考下表:
方法 路径 动作 路由名称 GET /article index article.index GET /article/create create article.create POST /article store article.store GET /article/{id} show article.show GET /article/{id}/edit edit article.edit PUT/PATCH /article/{id} update article.update DELETE /article/{id} destroy article.destroy
2. 跳转到项目根目录(windows进入dos系统),创建控制器:
php artisan make:controller Admin\ArticleController
3. 填充控制器对应Resource指定方法
注意:这几个方法不是自己随便定义的,是Resource路由规则规定好的,所以不要随便改变喔。
4. 创建文章数据库模型 及 迁移文件
php artisan make:model Models\Article -m
注意:我把数据库模型文件全部放进app/Models/目录下的,这个目录是自己创建的。
5. 填充迁移文件,设置数据库结构,并执行迁移创建articles数据库
(1) 填充迁移文件
increments('id');
$table->unsignedInteger('category_id')->comment('文章类别id')->default(0);
$table->string('category_name',20)->comment('文章类别名称')->default('其他');
$table->string('title',100)->comment('文章标题');
$table->string('author',30)->comment('文章作者')->default('未知作者');
$table->string('descr',255)->comment('文章简介')->nullable();
$table->string('image',255)->comment('文章导图');
$table->text('content')->comment('文章内容');
$table->unsignedTinyInteger('status')->comment('文章状态,1-草稿;2-发表')->default(1);
$table->unsignedInteger('click_count')->comment('文章点击数量')->default(0);
$table->unsignedTinyInteger('top_status')->comment('置顶状态,0-普通 1-置顶')->default(0);
$table->unsignedInteger('top_time')->comment('置顶时间')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('articles');
}
}
(2)跳转到项目根目录(windows打开dos系统),执行迁移,创建articles数据库
php artisan migrate
Laravel迁移相关知识点可以参考博文:laravel5.5数据库迁移入门实践
6. 配置Article.php数据库模型文件
7. 数据库批量填充测试数据
(1)跳转到项目根目录(windows进入dos系统),创建seeder文件
php artisan make:seed ArticlesTableSeeder
(2)工厂生成数据,操作文件\database\factories\ModelFactory.php
define(\App\Models\Article::class, function (\Faker\Generator $faker) {
$arr = [1=>'php', 2=>'mysql', 3=>'linux', 4=>'laravel'];
$k = mt_rand(1,4);
$category = [ $k,$arr[$k] ];
return [
'category_id' => $category[0],
'category_name' => $category[1],
'title' => $faker->title,
'author' => $faker->name,
'descr' => $faker->text,
'image' => $faker->imageUrl(),
'content' => $faker->text,
'status' => mt_rand(1,2),
'click_count' => $faker->numberBetween(100,3000),
'top_status' => mt_rand(0,1),
'top_time' => time()
];
});
(3)填充\database\seeds\ArticlesSeeder.php文件的run方法
make();
\App\Models\Article::insert( $articles->toArray() );
}
}
(4)添加ArticlesSeeder文件到\database\seeds\DatabaseSeeder.php中
call(ArticlesTableSeeder::class);
}
}
laravel填充数据相关知识可以参考博文:laravel5.5数据库之数据填充(实践)
8. 完成ArticleController.php控制器的业务逻辑方法
article = $article;
}
/**
* 显示文章列表.
*
* @return Response
*/
public function index(Request $request)
{
// 默认获取已发表文章
$status = $request->input('status') == 2 ? 2 : 1;
$list = $this->article->paginate(10, ['status'=>$status]);
return view('admin.article.index', compact('list','status'));
}
/**
* 创建新文章表单页面
*
* @return Response
*/
public function create()
{
$cate = [1=>'php', 2=>'mysql', 3=>'linux', 4=>'laravel'];
return view('admin.article.create',compact('cate'));
}
/**
* 将新创建的文章存储到存储器
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$data = $request->validate([
'category_id' => 'required',
'title' => 'required',
'author' => 'required',
'image' => 'required',
'status' => 'required',
'click_count' => 'required',
'descr' => 'nullable',
'content' => 'required'
]);
$cate = [1=>'php', 2=>'mysql', 3=>'linux', 4=>'laravel'];
$data['category_name'] = $cate[ $data['category_id'] ];
$re = $this->article->create($data);
return redirect()->route('article.index');
}
/**
* 显示指定文章
*
* @param int $id
* @return Response
*/
public function show($id)
{
$article = $this->article->find($id);
return view('admin.article.show', compact('article'));
}
/**
* 显示编辑指定文章的表单页面
*
* @param int $id
* @return Response
*/
public function edit($id)
{
$cate = [1=>'php', 2=>'mysql', 3=>'linux', 4=>'laravel'];
$article = $this->article->find($id);
return view('admin.article.edit', compact('article', 'cate'));
}
/**
* 在存储器中更新指定文章
*
* @param Request $request
* @param int $id
* @return Response
*/
public function update(Request $request, $id)
{
$data = $request->validate([
'status' => 'required'
]);
return $this->article->update($data, $id, "id");
}
/**
* 从存储器中移除指定文章
*
* @param int $id
* @return Response
*/
public function destroy($id)
{
return $this->article->delete($id);
}
}
注意:因为我封装了一层用来解耦的数据库操作层,所以没有直接操作数据库模型,仅供参考哈。
三、界面展示
终于写完了,我的模版文件就不展示了,看几张效果图:
四、补充
如果需要额外再添加其他方法,可以 在资源路由前面 定义方法,如:
// 注意:一定要放在resource资源路由上面哈
Route::post('test', 'ArticleController@test');
Route::resource('article', 'ArticleController');
如果还有疑问,欢迎留言讨论哈!