Laravel大型项目系列教程(一)

Laravel大型项目系列教程(一)

一、简介

本教程将使用Laravel完成一个多用户的博客系统,大概会包含如下内容:
  • 路由管理。
  • 用户管理,如用户注册、修改信息、锁定用户等。
  • 文章管理,如发表文章、修改文章等。
  • 标签管理,文章会有一到多个标签。
  • 数据库管理,如迁移、填充数据等。
  • Web表单验证。
  • Blade模版引擎。
  • 分页处理。
  • 安全处理。
  • 单元测试。
  • 部署到应用服务器Apache。

尽量保证每节教程完整并能运行,会在教程的最后附上这节教程的代码下载地址。
Tip:教程中必要的知识点都会有一个超链接

二、环境要求


三、Let's go!

1.新建一个Laravel项目

使用如下命令创建一个名为blog的Laravel项目:
$ composer create-project laravel/laravel blog --prefer-dist

创建完成之后进入到blog目录,修改app/config/app.php中的timezone为PRC、locale为zh,然后在blog目录下启动它自带的开发服务器:
$ php artisan serve
Laravel development server started on http://localhost:8000

打开浏览器输入localhost:8000,如果页面如下图就说明项目搭建完成了:

2.安装插件

在composer.json中增加:
"require-dev": {
"way/generators": "~2.0"
},

运行composer update安装,完成后在app/config/app.php的providers中增加:
'Way\Generators\GeneratorsServiceProvider'

运行php artisan是不是多了generate选项,它可以快速地帮我们创建想要的组件。

3.建立数据库

把app/config/database.php中connections下的mysql改成你自己的配置:
'mysql' => array(
'driver'    => 'mysql',
'host'      => 'localhost',
'database'  => 'blog',
'username'  => 'root',
'password'  => '',
'charset'   => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix'    => '',
),

需要在MySQL中先创建一个名为blog的数据库
配置完成之后,创建users表的数据库迁移文件:
$ php artisan migrate:make create_users_table --create=users

我们会发现在app\database\migrations下多了一个*_create_users_table.php文件,在这个文件中修改:
Schema::create('users', function(Blueprint $table)
{
$table->increments('id');
$table->string('email');
$table->string('password');
$table->string('nickname');
$table->boolean('is_admin')->default(0);
$table->boolean('block')->default(0);
$table->timestamps();
});

之后进行数据库迁移:
$ php artisan migrate

你会惊讶地发现在数据库中多了两张表users和migrations,users表就是我们定义的表,migrations表记录了迁移的信息。

4.创建User模型

数据库迁移完成之后我们将使用Eloquent ORM,这是Laravel让人着迷的重要原因之一。我们会发现在app\models下已经有一个User.php文件了,对其修改:
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\UserTrait;

class User extends Eloquent implements UserInterface {
use UserTrait;

protected $table = 'users';
protected $hidden = array('password', 'remember_token');
protected $fillable = array('nickname', 'email', 'password');
}

5.填充数据

有了User模型后,我们就可以向数据库填充数据了,在app/database/seeds下创建一个名为UserTableSeeder.php的文件,增加如下:
class UserTableSeeder extends Seeder {
public function run()
{
    User::create([
        'email'    => 'admin@shiyanlou.com',
        'password' => Hash::make(''),
        'nickname' => 'admin',
        'is_admin' => 1,
    ]);
}
}

然后在DatabaseSeeder.php中增加:
$this->call('UserTableSeeder');

之后就真正地向数据库填充数据:
$ php artisan db:seed

你可以查看数据库,会发现users表中多了一条记录。
详情可以查看Laravel中数据库的迁移和填充

6.创建视图模版

我们将使用Laravel中的Blade模版引擎,使用下面命令创建三个视图:
php artisan generate:view _layouts.default
php artisan generate:view _layouts.nav
php artisan generate:view _layouts.footer
php artisan generate:view index

之后你可以在app/views下发现多了一个index.blade.php和一个_layouts文件夹,在_layouts文件夹下有三个文件default.blade.php、footer.blade.php和nav.blade.php。我们将使用AmazeUI框架来做为前端框架,修改default.blade.php:
<!DOCTYPE html>
<html>
<head lang="zh">
<meta charset="UTF-8"/>
<title>ShiYanLou Blog</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport"
    content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no"/>
<meta name="renderer" content="webkit"/>
<meta http-equiv="Cache-Control" content="no-siteapp"/>
<link rel="alternate icon" type="image/x-icon" href="{{ URL::asset('i/favicon.ico') }}"/>
<link rel="stylesheet" href="//cdn.amazeui.org/amazeui/2.1.0/css/amazeui.min.css"/>
{{ HTML::style('css/custom.css') }}
</head>
<body>
<header class="am-topbar am-topbar-fixed-top">
<div class="am-container">
<h1 class="am-topbar-brand">
  <a href="/">ShiYanLou Blog</a>
</h1>
@include('_layouts.nav')
</div>
</header>

@yield('main')

@include('_layouts.footer')

<script src="//cdn.bootcss.com/jquery/2.1.3/jquery.min.js"></script>
<script src="//cdn.amazeui.org/amazeui/2.1.0/js/amazeui.min.js"></script>
</body>
</html>

URL::asset('i/favicon.ico')会生成http://localhost:8000/i/favicon.ico,HTML::style('css/custom.css')会生成<link media="all" type="text/css" rel="stylesheet" href="http://localhost:8000/css/custom.css";>,其中的i和css文件夹是放在public目录下的,public目录是项目的资源文件夹。@include('_layouts.nav')会包含app/views/_layouts/nav.blade.php文件,@yield('main')是用于模版继承的。

修改nav.blade.php:
<button class="am-topbar-btn am-topbar-toggle am-btn am-btn-sm am-btn-secondary am-show-sm-only"
    data-am-collapse="{target: '#collapse-head'}"><span class="am-sr-only">nav switch</span>
    <span class="am-icon-bars"></span></button>
<div class="am-collapse am-topbar-collapse" id="collapse-head">
<div class="am-topbar-right">
<a href="#" class="am-btn am-btn-primary am-topbar-btn am-btn-sm topbar-link-btn"><span class="am-icon-user"></span> Login</a>
</div>
</div>

修改footer.blade.php:
<footer class="footer">
<p>© 2015 By <a href="http://www.shiyanlou.com" target="_blank">www.shiyanlou.com</a></p>
</footer>

修改index.blade.php:
@extends('_layouts.default')

@section('main')
<div class="am-g am-g-fixed blog-g-fixed">
<div class="am-u-sm-12">
<h1>Welcome to ShiYanLou!</h1>
</div>
</div>
@stop

@extends('_layouts.default')会继承app/views/_layouts/default.blade.php文件,@yield('main')对应@section('main')并填充为其中的内容。

在public目录下新建两个文件夹i和css,在i文件夹里放置一个名为favicon.ico的图标,在css文件夹下新建一个名为custom.css的文件,修改如下:
.footer p {
color: #7f8c8d;
margin: 0;
padding: 15px 0;
text-align: center;
background: #2d3e50;
}

.topbar-link-btn {
color: #fff !important;
}

7.修改路由访问首页

视图已经有了,这时候需要把路由跟视图进行关联,修改app/routes.php如下:
Route::get('/', function()
{
return View::make('index');
});

不出意外,这时候访问localhost:8000会出现下图这样:

终于见到了亲手编写的第一个页面,是不是有点小激动啊?

8.创建登录视图

在nav.blade.php中修改登录超链接的地址:
<a href="{{ URL::to('login') }}" class="am-btn am-btn-primary am-topbar-btn am-btn-sm topbar-link-btn"><span class="am-icon-user"></span> Login</a>

URL::to('login')会生成http://localhost:8000/login这个地址。

创建login.blade.php:
$ php artisan generate:view login

修改login.blade.php:
@extends('_layouts.default')

@section('main')
<div class="am-g am-g-fixed">
<div class="am-u-lg-6 am-u-md-8">
  <br/>
  @if (Session::has('message'))
    <div class="am-alert am-alert-danger" data-am-alert>
      <p>{{ Session::get('message') }}</p>
    </div>
  @endif
  @if ($errors->has())
    <div class="am-alert am-alert-danger" data-am-alert>
      <p>{{ $errors->first() }}</p>
    </div>
  @endif
  {{ Form::open(array('url' => 'login', 'class' => 'am-form')) }}
    {{ Form::label('email', 'E-mail:') }}
    {{ Form::email('email', Input::old('email')) }}
    <br/>
    {{ Form::label('password', 'Password:') }}
    {{ Form::password('password') }}
    <br/>
    <label for="remember_me">
      <input id="remember_me" name="remember_me" type="checkbox" value="1">
      Remember Me
    </label>
    <br/>
    <div class="am-cf">
      {{ Form::submit('Login', array('class' => 'am-btn am-btn-primary am-btn-sm am-fl')) }}
    </div>
  {{ Form::close() }}
  <br/>
</div>
</div>
@stop

在routes.php中增加:
Route::get('login', function()
{
return View::make('login');
});

这时候访问localhost:8000/login或者点击导航条的Login按钮会出现下图这样:

9.实现登录

创建用户登录后主页:
$ php artisan generate:view home

修改home.blade.php:
@extends('_layouts.default')

@section('main')
<div class="am-g am-g-fixed blog-g-fixed">
<div class="am-u-sm-12">
  <h1>Hello {{ { Auth::user()->nickname </h1>} }}
</div>
</div>
@stop

修改nav.blade.php:
<div class="am-collapse am-topbar-collapse" id="collapse-head">
@if (Auth::check())
<ul class="am-nav am-nav-pills am-topbar-nav am-topbar-right">
  <li class="am-dropdown" data-am-dropdown>
    <a class="am-dropdown-toggle" data-am-dropdown-toggle href="javascript:;">
      <span class="am-icon-users"></span> {{ { Auth::user()->nickname } }} <span class="am-icon-caret-down"></span>
    </a>
    <ul class="am-dropdown-content">
      <li><a href="{{ URL::to('logout') }}"><span class="am-icon-power-off"></span> Exit</a></li>
    </ul>
  </li>
</ul>
@else
<div class="am-topbar-right">
  <a href="{{ URL::to('login') }}" class="am-btn am-btn-primary am-topbar-btn am-btn-sm topbar-link-btn"><span class="am-icon-user"></span> Login</a>
</div>
@endif
</div>

在Routes.php中增加:
Route::post('login', array('before' => 'csrf', function()
{
$rules = array(
    'email'       => 'required|email',
    'password'    => 'required|min:6',
    'remember_me' => 'boolean',
);
$validator = Validator::make(Input::all(), $rules);
if ($validator->passes())
{
    if (Auth::attempt(array(
        'email'    => Input::get('email'),
        'password' => Input::get('password'),
        'block'    => 0), (boolean) Input::get('remember_me' ) ))
    {
        return Redirect::intended('home');
    } else {
        return Redirect::to('login')->withInput()->with('message', 'E-mail or password error');
    }
} else {
    return Redirect::to('login')->withInput()->withErrors($validator);
}
} ));

Route::get('home', array('before' => 'auth', function()
{
return View::make('home');
} ));

下面就可以尝试用户登录了,如果输入信息有误,会出现错误信息如:

登录成功后会出现下图这样:

这里我们使用了Laravel自带的身份验证Auth,你也可以使用更加强大的SentryWeb表单验证用了Validator,View和Redirect详细可以查看视图和响应文档,还使用了路由过滤器,csrf过滤器可以使我们轻松地防御csrf攻击。

10.退出登录

在routes.php中增加:
Route::get('logout', array('before' => 'auth', function()
{
Auth::logout();
return Redirect::to('/');
}));

现在你就可以实现退出功能了,点击Exit:

退出后会跳转到主页。

11.小结

至此简单的用户登录功能就完成了,你除了要完成上述的例子外,还要完成记住我的功能哦!你可以通过下面途径来完成:

11 个评论

zfeig

zfeig

其实,我也刚写完一个多用户blog,不过觉得你的更规范!http://blog.csdn.net/zhangfei8625/article/details/43084977
2015-01-24 15:10
hutaoseven

hutaoseven

我在Model.php(laravel 4.2.16)中没有找到guar这个属性,有的只是:
protected $fillable = array();//默认可插入字段为空
protected $guarded = array('*');//默认保护所有字段(不可插入任何字段)。所谓的黑名单。
2015-01-24 17:36
hutaoseven

hutaoseven 回复 hutaoseven

是guard属性没有!,如果你也遇到此问题,把guard替换为fillable即可。项目很赞,感谢老大!
2015-01-24 17:49
实验楼

实验楼 回复 zfeig

我去看了~评论了~这一方面也是刚刚接触~以后可以多多交流~
2015-01-25 17:35
实验楼

实验楼 回复 hutaoseven

你也很赞~啦啦啦
2015-01-25 17:36
实验楼

实验楼 回复 hutaoseven

已经改了~谢谢哈~
2015-01-30 10:16
sujata

sujata

timezone为RPC
should be PRC
2015-01-31 12:09
实验楼

实验楼 回复 sujata

哦哦~谢谢~
2015-01-31 14:32
sujata

sujata

"在app/database/seeds下创建一个名为UsersSeeder.php的文件"
应为:创建一个名为UserTableSeeder.php的文件.
内容里丢了一个array:
<?php
class UserTableSeeder extends Seeder {

public function run()

{
User::create(array(

'email' => 'admin@shiyanlou.com',

'password' => Hash::make(''),

'nickname' => 'admin',

'is_admin' => 1,

));

}

}
2015-01-31 19:12
sujata

sujata

登录和退出登录不成功的解决办法
routes.php中Route::get('login', function()改成Route::get('/login', function(),这样写可以登录成功,否则不行。
退出登录不成功。查http://stackoverflow.com/questions/23242533/laravel-redirect-with-logout-not-working,这篇文章说要在数据库users表中加一行column,名为 "remember_token",nullable VARCHAR(100), TEXT。这样可以成功退出登录。
2015-02-01 10:38
fugeng

fugeng

这是什么版本?
2015-03-30 12:23

要回复文章请先登录注册