十分钟完成博客系统搭建
本篇开始我们将正式开始博客项目的代码编写,借助于 Laravel 的强大功能,我们可以在十分钟内快速搭建起一个博客应用,当然这其中不包括任何博客核心功能之外的东西,也不包括后台管理系统(这些我们在后续章节中会一一加进来)。
1、创建文章数据表及其模型(0:00~2:30)
我们已经在上一篇中为博客项目完成了大部分准备工作,现在首先要做的就是为这个项目创建一个新的文章表 posts
及该表对应的模型类 Post
,使用如下 Artisan 命令即可完成这两个创建工作:
php artisan make:model -m Models/Post
上述命令会做两件事情:
- 在
app/Models
目录下创建模型类Post
; - 创建
posts
表的数据库迁移,该迁移文件位于database/migrations
目录下。
编辑 database/migrations
目录下刚生成的这个迁移文件内容如下:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('slug')->unique();
$table->string('title');
$table->text('content');
$table->softDeletes();
$table->timestamp('published_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}
我们在默认生成的迁移文件基础上新增五个额外的列:
-
slug
:将文章标题转化为 URL 的一部分,以利于SEO -
title
:文章标题 -
content
:文章内容 -
published_at
:文章正式发布时间 -
deleted_at
:用于支持软删除
运行数据库迁移命令:
php artisan migrate
最后修改生成的默认 app/Models/Post.php
文件内容如下:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $dates = ['published_at'];
public function setTitleAttribute($value)
{
$this->attributes['title'] = $value;
if (! $this->exists) {
$this->attributes['slug'] = str_slug($value);
}
}
}
2、使用测试数据填充文章表(2:30~5:00)
有了第一步操作,现在文章已经有了寄身之所,接下来我们不妨填充一些初始化数据到数据表 posts
中。这里我们要用到 Laravel 的模型工厂功能。
运行如下 Artisan 命令创建一个模型工厂文件:
php artisan make:factory PostFactory --model=Models/Post
添加如下代码到 database/factories
目录下的 PostFactory.php
文件中:
<?php
use Faker\Generator as Faker;
$factory->define(App\Models\Post::class, function (Faker $faker) {
return [
'title' => $faker->sentence(mt_rand(3, 10)),
'content' => join("\n\n", $faker->paragraphs(mt_rand(3, 6))),
'published_at' => $faker->dateTimeBetween('-1 month', '+3 days'),
];
});
运行如下 Artisan 命令创建一个新的填充类文件:
php artisan make:seeder PostsTableSeeder
编写在 database/seeds
目录下新生成的 PostsTableSeeder
类文件如下:
<?php
use Illuminate\Database\Seeder;
use App\Models\Post;
class PostsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Post::truncate(); // 先清理表数据
factory(Post::class, 20)->create(); // 一次填充20篇文章
}
}
最后修改 database/seeds
目录下的 DatabaseSeeder.php
内容如下:
<?php
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
Model::unguard();
// $this->call(UsersTableSeeder::class);
$this->call(PostsTableSeeder::class);
}
}
运行数据库填充命令填充初始化数据:
php artisan db:seed
该命令执行成功后,posts
表中会多出 20 行记录:
3、创建配置文件(5:00~5:30)
我们还需要为博客做一些配置,比如标题和每页显示文章数。时间不多了,让我们快速行动起来。
在 config
目录下创建一个新的配置文件 blog.php
,编辑其内容如下:
<?php
return [
'title' => 'My Blog',
'posts_per_page' => 5
];
在 Laravel 中,可以轻松通过辅助函数 config()
访问这些配置项,例如,config('blog.title')
将会返回 title
配置项的值。
此外,如果需要的话你还可以去 config/app.php
修改时区配置。
4、创建路由和控制器(5:30~7:30)
接下来修改 routes/web.php
文件如下:
Route::get('/', function () {
return redirect('/blog');
});
Route::get('/blog', 'BlogController@index')->name('blog.home');
Route::get('/blog/{slug}', 'BlogController@showPost')->name('blog.detail');
这样,如果访问 http://blog57.test/
的话,页面会重定向到 http://blog57.test/blog
,而访问 http://blog57.test/blog
时,会调用 BlogController
的 index
方法来处理业务逻辑并渲染页面。同理访问 http://blog57.test/blog/POST-TITLE
时,会调用 BlogController
的 showPost
方法,同时会将 POST-TITLE
的值作为参数传递给 showPost
方法。
下面我们就来创建这个控制器 BlogController
。
首先,使用 Artisan 命令生成一个空的控制器:
php artisan make:controller BlogController
一个新的 BlogController.php
文件已经生成到 app/Http/Controllers
目录下,编辑其内容如下:
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Carbon\Carbon;
use Illuminate\Http\Request;
class BlogController extends Controller
{
public function index()
{
$posts = Post::where('published_at', '<=', Carbon::now())
->orderBy('published_at', 'desc')
->paginate(config('blog.posts_per_page'));
return view('blog.index', compact('posts'));
}
public function showPost($slug)
{
$post = Post::where('slug', $slug)->firstOrFail();
return view('blog.post', ['post' => $post]);
}
}
在控制器中,我们使用 Eloquent ORM 与数据库进行交互,并使用辅助函数 view()
渲染视图。
如果要查看应用中的所有路由,可以使用如下命令:
php artisan route:list
5、创建视图(7:30~10:00)
剩下的就是创建两个视图用来显示结果了:一个用于显示文章列表,一个用于显示文章详情。
在 resources/views
目录下创建一个新的目录 blog
。然后在该目录下创建一个新的视图文件 index.blade.php
。使用 .blade.php
后缀的目的在于告知 Laravel 该视图文件使用 Blade 模板。编辑 index.blade.php
文件内容如下:
<html>
<head>
<title>{{ config('blog.title') }}</title>
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>{{ config('blog.title') }}</h1>
<h5>Page {{ $posts->currentPage() }} of {{ $posts->lastPage() }}</h5>
<hr>
<ul>
@foreach ($posts as $post)
<li>
<a href="{{ route('blog.detail', ['slug' => $post->slug]) }}">{{ $post->title }}</a>
<em>({{ $post->published_at }})</em>
<p>
{{ str_limit($post->content) }}
</p>
</li>
@endforeach
</ul>
<hr>
{!! $posts->render() !!}
</div>
</body>
</html>
十分钟博客的最后一步就是就是创建显示文章详情的视图。在 resources/views/blog
目录下新建视图文件 post.blade.php
,编辑其内容如下:
<html>
<head>
<title>{{ $post->title }}</title>
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>{{ $post->title }}</h1>
<h5>{{ $post->published_at }}</h5>
<hr>
{!! nl2br(e($post->content)) !!}
<hr>
<button class="btn btn-primary" onclick="history.go(-1)">
« Back
</button>
</div>
</body>
</html>
好了,接下来我们可以去浏览器中进行测试了,访问 http://blog57.test
,页面显示如下:
文章详情页显示如下:
54 Comments
Call to undefined function factory() 没有这个方法,在哪里添加
填充数据显示Target class [DatabaseSeeder] does not exist. , 用composer dump-auto重新加载了也没用
请问setTitleAttribute是如何自动运行的添加slug字段的
SetTitleAttribute是访问器,具体看下这里:https://laravelacademy.org/post/9708