基于Laravel开发博客应用系列 —— 十分钟搭建博客系统


本节开始我们将正式开始博客项目的代码编写,借助于 Laravel 5.1 的强大功能,我们可以在十分钟内搭建起一个博客应用,当然这其中不包括任何花里胡哨的点缀之物,也不包括后台管理系统(这些我们在后续章节中会一一加进来)。

1、创建文章数据表及其模型(0:00~2:30)

我们已经在上一节中为博客项目完成了大部分准备工作,现在首先要做的就是为这个项目创建一个新的文章表 posts 及该表对应的模型类 Post,使用如下Artisan命令即可完成这两个创建工作:

  1. php artisan make:model --migration Post

上述命令会做两件事情:

  • app 目录下创建模型类 App\Post
  • 创建用于创建 posts 表的迁移,该迁移文件位于 database/migrations 目录下。

注:如果不了解什么是迁移,可参考 Laravel 迁移文档。

编辑 database/migrations 目录下刚生成的这个迁移文件内容如下:

  1. <?php
  2.  
  3. use Illuminate\Database\Schema\Blueprint;
  4. use Illuminate\Database\Migrations\Migration;
  5.  
  6. class CreatePostsTable extends Migration
  7. {
  8.  
  9. /**
  10. * Run the migrations.
  11. */
  12. public function up()
  13. {
  14. Schema::create('posts', function (Blueprint $table) {
  15. $table->increments('id');
  16. $table->string('slug')->unique();
  17. $table->string('title');
  18. $table->text('content');
  19. $table->timestamps();
  20. $table->timestamp('published_at')->index();
  21. });
  22. }
  23.  
  24. /**
  25. * Reverse the migrations.
  26. */
  27. public function down()
  28. {
  29. Schema::drop('posts');
  30. }
  31. }

我们在默认生成的迁移文件基础上新增四个额外的列:

  • slug:将文章标题转化为URL的一部分,以利于SEO
  • title:文章标题
  • content:文章内容
  • published_at:文章正式发布时间

登录到 Homestead 虚拟机项目根目录(~/Code/vagrant/blog)运行迁移命令:

  1. php artisan migrate

最后修改生成的默认 app/Post.php 文件内容如下:

  1. <?php
  2.  
  3. namespace App;
  4.  
  5. use Illuminate\Database\Eloquent\Model;
  6.  
  7. class Post extends Model
  8. {
  9. protected $dates = ['published_at'];
  10.  
  11. public function setTitleAttribute($value)
  12. {
  13. $this->attributes['title'] = $value;
  14.  
  15. if (! $this->exists) {
  16. $this->attributes['slug'] = str_slug($value);
  17. }
  18. }
  19. }

2、使用测试数据填充文章表(2:30~5:00)

有了第一步操作,现在文章已经有了寄身之所,接下来我们不妨创建一些随机数据填充到数据表 posts 中。这里我们要用到 Laravel 5.1 的模型工厂功能。

添加如下代码到 database/factories 目录下的 ModelFactory.php 文件中:

  1. $factory->define(App\Post::class, function ($faker) {
  2. return [
  3. 'title' => $faker->sentence(mt_rand(3, 10)),
  4. 'content' => join("\n\n", $faker->paragraphs(mt_rand(3, 6))),
  5. 'published_at' => $faker->dateTimeBetween('-1 month', '+3 days'),
  6. ];
  7. });

然后修改 database/seeds 目录下的 DatabaseSeeder.php 内容如下:

  1. <?php
  2.  
  3. use Illuminate\Database\Seeder;
  4. use Illuminate\Database\Eloquent\Model;
  5.  
  6. class DatabaseSeeder extends Seeder
  7. {
  8. /**
  9. * Run the database seeds.
  10. */
  11. public function run()
  12. {
  13. Model::unguard();
  14. $this->call('PostTableSeeder');
  15. }
  16.  
  17. }
  18.  
  19. class PostTableSeeder extends Seeder
  20. {
  21. public function run()
  22. {
  23. App\Post::truncate();
  24. factory(App\Post::class, 20)->create();
  25. }
  26. }

最后,还是在 Homestead 虚拟机项目根目录下运行如下 Artisan 命令将随机数据插入数据库:

  1. php artisan db:seed

该命令执行成功后,posts 表中会多出20行记录。

3、创建配置文件(5:00~5:30)

我们还需要为博客做一些配置,比如标题和每页显示文章数。时间不多了,让我们快速行动起来。

config 目录下创建一个新的配置文件 blog.php,编辑其内容如下:

  1. <?php
  2. return [
  3. 'title' => 'My Blog',
  4. 'posts_per_page' => 5
  5. ];

在 Laravel 5.1 中,可以轻松通过帮助函数 config() 访问这些配置项,例如,config('blog.title') 将会返回 title 配置项的值。

此外,如果需要的话你还可以去 config/app.php 修改时区配置。

4、创建路由和控制器(5:30~7:30)

接下来修改 app/Http/routes.php 文件如下:

  1. <?php
  2.  
  3. get('/', function () {
  4. return redirect('/blog');
  5. });
  6.  
  7. get('blog', 'BlogController@index');
  8. get('blog/{slug}', 'BlogController@showPost');

这样,如果访问 http://blog.app/ 的话,页面会重定向到 http://blog.app/blog,而访问 http://blog.app/blog 时,会调用  BlogControllerindex 方法来处理业务逻辑并渲染页面。同理访问 http://blog.app/blog/POST-TITLE 时,会调用  BlogControllershowPost 方法,同时会将 POST-TITLE 的值作为参数传递给 showPost 方法。

下面我们就来创建这个控制器 BlogController

首先,使用 Artisan 命令生成一个空的控制器:

  1. php artisan make:controller BlogController --plain

注:--plain 命令用于创建一个空的控制器而不是标准的 RESTful 风格控制器。

一个新的 BlogController.php 文件已经生成到 app/Http/Controllers 目录下,编辑其内容如下:

  1. <?php
  2.  
  3. namespace App\Http\Controllers;
  4.  
  5. use App\Post;
  6. use Carbon\Carbon;
  7.  
  8. class BlogController extends Controller
  9. {
  10. public function index()
  11. {
  12. $posts = Post::where('published_at', '<=', Carbon::now())
  13. ->orderBy('published_at', 'desc')
  14. ->paginate(config('blog.posts_per_page'));
  15.  
  16. return view('blog.index', compact('posts'));
  17. }
  18.  
  19. public function showPost($slug)
  20. {
  21. $post = Post::whereSlug($slug)->firstOrFail();
  22. return view('blog.post')->withPost($post);
  23. }
  24. }

在控制器中,我们使用 Eloquent ORM 与数据库进行交互,并使用辅助函数 view() 渲染视图。

如果要查看应用中的所有路由,可以使用如下命令:

  1. php artisan route:list

5、创建视图(7:30~10:00)

剩下的就是创建两个视图用来显示结果了:一个用于显示文章列表,一个用于显示文章详情。

resources/views 目录下创建一个新的目录 blog。然后在该目录下创建一个新的视图文件 index.blade.php。使用 .blade.php 后缀的目的在于告知 Laravel 该视图文件使用 Blade 模板。编辑 index.blade.php 文件内容如下:

  1. <html>
  2. <head>
  3. <title>{{ config('blog.title') }}</title>
  4. <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
  5. </head>
  6. <body>
  7. <div class="container">
  8. <h1>{{ config('blog.title') }}</h1>
  9. <h5>Page {{ $posts->currentPage() }} of {{ $posts->lastPage() }}</h5>
  10. <hr>
  11. <ul>
  12. @foreach ($posts as $post)
  13. <li>
  14. <a href="/blog/{{ $post->slug }}">{{ $post->title }}</a>
  15. <em>({{ $post->published_at }})</em>
  16. <p>
  17. {{ str_limit($post->content) }}
  18. </p>
  19. </li>
  20. @endforeach
  21. </ul>
  22. <hr>
  23. {!! $posts->render() !!}
  24. </div>
  25. </body>
  26. </html>

十分钟博客的最后一步就是就是创建显示文章详情的视图。在 resources/views/blog 目录下新建视图文件 post.blade.php,编辑其内容如下:

  1. <html>
  2. <head>
  3. <title>{{ $post->title }}</title>
  4. <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
  5. </head>
  6. <body>
  7. <div class="container">
  8. <h1>{{ $post->title }}</h1>
  9. <h5>{{ $post->published_at }}</h5>
  10. <hr>
  11. {!! nl2br(e($post->content)) !!}
  12. <hr>
  13. <button class="btn btn-primary" onclick="history.go(-1)">
  14. « Back
  15. </button>
  16. </div>
  17. </body>
  18. </html>

好了,接下来我们可以去浏览器中进行测试了,访问 http://blog.app,页面显示如下:

Laravel创建的博客首页

文章详情页显示如下:

Laravel创建的博客文章页