开发环境 Windows 篇
用windows的同学们有福了,你无需任何繁琐的配置都可以很方便的开发 laravel,这就是laragon。用 laragon 做起 laravel 开发,真的无比方便好用。
它里面自带composer,php,mysql,redis memcached,还包含有cmder这个非常好用的命令行。
使用中文
点右键,preferences,现在可以把language设置成chinese了,其他的一切都保持默认就好。
Tips: 如果你的 apache 启动报错,可尝试将右键,参数里的ssl端口设置为其他端口,例如3000
开始来跑 laravel 项目了
右键,快速创建,选laravel,输入项目名称meetup。
等命令跑完后,laragon会自动配置后缀dev的虚拟机,打开chrome浏览器,输入
看到这个画面就说明,你已经成功的跑起 laravel 了
1. The Laravel Way
laravel 的根本骨架是上面的 mvc 结构,不过这一集只来关注 route -> controller -> view 的这条线。
到 routes/web.php 中修改
<?php
use Illuminate\Support\Facades\Route;
// 引入控制器文件
use App\Http\Controllers\WelcomeController;
Route::get('/',[WelcomeController::class,'index']);
Route::get('about', [WelcomeController::class,'about']);
添加 controller
php artisan make:controller WelcomeController
启动项目
php artisan serve
views
- 将提供的
assets文件夹,拷贝到meetup/public目录。 - 在
resources/views目录中新建一个叫做welcome文件夹。 - 把
index.html和about.html拷贝到resources/views/welcome,并把文件后缀名都改为blade.php。
1. controller 里传数据
public function index()
{
$issues = [
['title' => 'PHP lovers'],
['title' => 'Rails and Laravel']
];
return view('welcome.index')->with('issues', $issues);
}
删除一条重复的 issue,然后给另一条做 foreach 循环
@foreach($issues as $issue)
<li class="...">
...
<a href="issues_show.html">{{$issue['title']}}</a>
...
</li>
@endforeach
Sub-Views
分离为一个 子视图文件
- 在
resources/views/welcome中添加活动列表_issue_list.blade.php文件。 - 将
index.blade.php中活动列表部分的代码,剪切到_issue_list.blade.php中。 - 再到
index.blade.php中加上
@include('welcome._issue_list')
数据库
据库连接
这次相关的配置文件是根目录下的 .env 文件,里面写明了要使用的数据库和用到的账号密码。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=meetup
DB_USERNAME=root
DB_PASSWORD=root
建立数据表结构
更改数据库的表结构,laravel 给出的方法是 migration laravel.com/docs/5.5/mi…
php artisan make:migration create_issues_table --create=issues
生成的文件名的前面是时间戳,2017_11_29… 今天就是 2017年11月29号。里面可以添加需要的字段。
至于database/migrations文件夹中已经默认存在的create_users_table和create_password_resets_table是我们后面做用户登陆注册需要用到的,咱们暂时先不需要关注它。
public function up()
{
Schema::create('issues', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->timestamps();
});
}
运行
php artisan migrate
来把内容真正写进 mysql 数据库。
建立 model
model 文件要放在 app/Models 下面,名字叫 Issue.php
php artisan make:model Models/Issue
class Issue extends Model
{
}
这里的 class 命名是很关键的,如果数据库中的表名是issues,那这里的class名就必须是 Issue,也就是首字母大写,同时变成单数。为啥要这样?因为这样laravel就可以建立自动的 class 到 table 的映射关系了,以后要操作issues这张表,就无比的方便。
Tips:如果你需要将
model和对应的migration一下全部建出来,下次也可以直接使用php artisan make:model Models/Issue -m这一条命令。这样他会同时生成model和migration。
这样就可以打开 laravel tinker 来真正对这样表进行操作了,具体可以参考 laravel.com/docs/5.5/ar…
php artisan tinker
插入需要的记录
use App\Models\Issue
Issue::create(['title' => 'PHP Lover'])
Issue::create(['title' => 'Rails and Laravel'])
Issue::all()
屏幕提示一个错误信息 Illuminate\Database\Eloquent\MassAssignmentException with message 'title'
这个是 laravel 为了防止坏人恶意提交数据攻击网站,而采用的自我保护机制。你想啊,如果不加说明,坏蛋们就可以在表单中人为植入其他的参数。
要做的修改非常简单,就是到 Issue模型中,添加白名单。
class Issue extends Model
{
protected $fillable = ['title'];
}
修改 controller 和 view
现在在 controller 中读取数据
use App\Models\Issue;
class WelcomeController extends Controller
{
public function index()
{
$issues = Issue::orderBy('created_at', 'desc')
->take(2)
->get();
return view('welcome.index')->with('issues', $issues);
}
}
Tips:
orderBy的意思是排序。created_at是添加数据的时候,laravel自动帮添加的当前时间。desc是倒序(从大到小)。这样最新发布的issue会就在最上面了。take(2)的意思,是说这里只读取两条数据。
再到 _issue_list.blade.php 中在稍作修改就好了。
{{$issue->title}}
CURD
现在有了 issue 也就是活动信息这个东东,后面就开始对他 Create Update Read Delete 了。
这一集只是开始,瞄准 issue的展示和删除。关于 CURD 比较详细的解释,参考 laravel.com/docs/5.5/el…
往表添加字段
添加 content 到 issue
首先运行一下 migration
php artisan make:migration add_content_to_issues_table --table=issues
class AddContentToIssuesTable extends Migration
{
public function up()
{
Schema::table('issues', function (Blueprint $table) {
$table->text('content');
});
}
public function down()
{
Schema::table('issues', function (Blueprint $table) {
$table->dropColumn('content');
});
}
}
别忘了php artisan migrate,来跑一下迁移命令。
Tips: down里面写的是 up的反操作。将来如果写错了,将来可以通过php artisan migrate:rollback这一条命令来回滚对数据库的操作。
插入一下数据
下面打开 php artisan tinker
use App\Models\Issue
$i = Issue::find(1)
$i->content = "The PHP Framework For Web Artisans"
$i->save()
$i = Issue::find(2)
$i->content = "Imagine what you could build if you learned Ruby on Rails ..."
$i->save()
添加路由
在web.php中加上
Route::get('issues/{issue}', [IssuesController::class,'show']);
新建控制器
<?php
namespace App\Http\Controllers;
use App\Models\Issue;
use Illuminate\Http\Request;
class IssuesController extends Controller
{
public function show($id)
{
$issue = Issue::find($id); // 查询数据
// return $issue;
return view('issues.show')->with('issue',$issue);
}
}
使用命名路由
// 使用命名路由
Route::get('issues/{issue}', [IssuesController::class,'show'])->name('issues.show');
view
<a href="{{route('issues.show',$issue->id)}}">{{$issue->title}}</a>
删除数据
public function destroy($id)
{
Issue::destroy($id);
return redirect('/');
}
新增数据
Route::post('add', [IssuesController::class,'store'])->name('issues.store');
view
<form class="am-form" action="{{route('issues.store')}}" method="post">
{{csrf_field()}}
<fieldset>
<div class="am-form-group">
<label>标题</label>
<input type="text" placeholder="输入活动标题" name="title">
</div>
<div class="am-form-group">
<label>内容</label>
<textarea rows="5" name="content"></textarea>
</div>
<button type="submit" class="am-btn am-btn-default">提交</button>
</fieldset>
</form>
将数据添加到数据库中
public function store(Request $request)
{
Issue::create($request->all());
return redirect('/');
}
Issue.php模型中,加上content白名单
protected $fillable = ['title', 'content'];
分页
public function index()
{
// $issues = Issue::orderBy('created_at','desc')->get();
$issues = Issue::orderBy('created_at', 'desc')->paginate(5);
return view('issues.index')->with('issues',$issues);
}
1.修改controller,将之前查询用的get(),改为paginate(5)。 这里5的意思是说,每页显示5条数据。
issues/index.blade.php中,用{{ $issues->links() }},代替之前写死的分页代码。
1. 修改
view
<div class="am-container">
<div class="header">
<div class="am-g">
<h1>修改活动</h1>
</div>
<hr>
</div>
<form class="am-form" action="{{route('issues.update',$issue->id)}}" method="post">
{{ csrf_field() }}
{{ method_field('PUT') }}
<fieldset>
<div class="am-form-group">
<label>标题</label>
<input type="text" placeholder="输入活动标题" name="title" value="{{$issue->title}}">
</div>
<div class="am-form-group">
<label>内容</label>
<textarea rows="5" name="content" >{{$issue->content}}</textarea>
</div>
<button type="submit" class="am-btn am-btn-default">提交</button>
</fieldset>
</form>
</div>
因为这里使用了put动词,而form表单并不能发起put、patch和delete请求。 laravel的解决方式是,添加 {{ method_field('PUT') }},来伪造一个put请求。
Route::put('update/{issue}', [IssuesController::class,'update'])->name('issues.update');
// 修改
public function update(Request $request,$id)
{
$issue = Issue::find($id);
$issue->update($request->all());
return redirect(route('issues.show',$id));
//return view('issues.show')->with('issue',$issue);
}
一对多
这也就是我们数据库关联中所说的一对多关系。 做评论功能,关注的核心问题也是has many关系。一个issue,对应多个comment。
1. 创建 model 和 migration
php artisan make:model Models/Comment -m
修改 migration 文件
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->increments('id');
$table->integer('issue_id');
$table->string('name');
$table->string('email');
$table->text('content');
$table->timestamps();
});
}
运行migrate,生成comments表。
php artisan migrate
Tips: 为了体现归属关系,也就是一个 issue 对应多个 comment 的关系。要在comments中添加一个新的字段issue_id,这个在后面会有妙用。
view
<form class="am-form" method="post" action="{{route('comments.store')}}">
{{csrf_field()}}
<input type="hidden" name="issue_id" value="{{$issue->id}}">
...
</form>
Tips: 因为comments表中,有一个issue_id。这里就需要放一个隐藏的input,将当前issue的id传递过去。
Route::post('comments', [CommentsController::class,'store'])->name('comments.store');
class CommentsController extends Controller
{
public function store(Request $request)
{
return $request->all();
}
}
当前发布评论所在页面的issue_id已经传递过来了
进一步修改为
//一定记得要use model
use App\Models\Comment;
class CommentsController extends Controller
{
public function store(Request $request)
{
Comment::create($request->all());
return back();
}
}
建立一对多的关系
第一步,到Issue.php模型中添加
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Issue extends Model
{
protected $fillable = ['title', 'content'];
public function comments()
{
return $this->hasMany('App\Models\Comment');
}
}
Tips: 一个issue有很多个comment,所以这里要用复数的comments。
第二步,到Comment.php模型 中,添加
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $fillable = ['issue_id', 'name', 'email', 'content'];
public function issue()
{
return $this->belongsTo('App\Models\Issue');
}
}
Tips: 每个comment只都属于一个issue,所以这里的issue是单数。
好了,就是这简单的两步。issue与comment的关联关系就已经定义完毕了。 再来刷新一下页面,comments出现了。
最后一步,完成show方法
public function show($id)
{
$issue = Issue::find($id);
$comments = $issue->comments;
return view('issues.show', compact('issue', 'comments'));
}
Tips: 如果需要发送多个数据到模板,可以使用php的compact函数来简化代码。
view
@foreach($comments as $comment)
<li class="am-comment">
<img src="/assets/img/avatar2.png" alt="" class="am-comment-avatar" width="48" height="48">
<div class="am-comment-main">
<header class="am-comment-hd">
<div class="am-comment-meta">
<span class="am-comment-author">{{$comment->name}}</span>
{{$comment->created_at->diffForHumans()}}
</div>
</header>
<div class="am-comment-bd">{{$comment->content}}</div>
</div>
</li>
@endforeach
laravel 常用命令
laravel 的命令有挺多的,不过常用的也就是那么几条,我们这次课程也都基本用到了。
常用的命令和意义我都列出来了,如果记不住,可以将下面的表格截图保存一份,照着多打个几次,慢慢就都记住了。
| 命令 | 意义 |
|---|---|
| php artisan make:controller IssuesController | 新建控制器 |
| php artisan make:controller IssuesController -r | 新建控制器并自动生成对应 RESTful 风格路由相关 CURD 方法 |
| php artisan make:migration create_issues_table --create=issues | 新建一个迁移文件 |
| php artisan migrate | 运行迁移,将迁移文件的内容写入数据库中 |
| php artisan migrate:rollback | 回滚上一次迁移的内容 |
| php artisan make:model Models/Issue | 新建模型 |
| php artisan make:model Models/Issue -m | 同时生成模型和对应的迁移文件 |
| php artisan tinker | 使用命令行来调试 Laravel、操作模型等 |
| php artisan route:list | 打印出所有的路由 |
控制器
作用就是整个程序的逻辑部分,可以调用模型做一些数据处理,还可以显示模板,发送数据到模板,跳转等等。 如果需要发送多个数据到模板,那么可以使用compact函数来简化代码。
模型
模型一般都放在App\Models中。初学模型,暂时也不用太深入,知道我们是使用模型来操作数据库的就好。目前需要掌握的也只有定义 白名单 和关联。我们实现了issues和comments的一对多关联,comments表中一定要有issue_id来做对应。模型的关联除了咱们这次课用到的一对多外,还有一对一,多对多,这些我会在后续的课程再跟大家介绍。
这里还是用 php artisan tinker来看一下这两个例子。
迁移
数据库中,有一个migrations表,这里记录的是所有已经跑过的迁移列表,如果这里已经有记录了,那你再跑php artisan migrate,他是不会重复执行的。换句话说,就是只会运行之前从没有跑过的迁移文件。
如果你觉得迁移用的不习惯,觉得直接动手使用sequal pro或者navicat这类软件建表更方便,那其实也完全没有任何问题的,laravel一样可以用的好好的。
布局模板
再来看模板部分,将页面相同的公共部分,抽离出来,放在layout/app.blade.php,并且加上@yield('content')
其他的页面
@extends('layouts.app')
@section('content')
<!-- 不同的部分 -->
@endsection
参数
路由中的issues.show的对应的uri包含了这样一个有大括号的路径,/issues/{issue},那么超链接那里就可以写{{route('issues.show', 10)}},这个10,就会替换掉{issue},生成的路径也就是/issues/10。
除此外,在控制器的方法中,直接可以就可以使用这个$id,也就是传过来的10,而不用像其他框架那样要用$_GET['id']来取值了。
function show($id) {
return $id;
}
api.php
routes文件夹中,除了web.php外,还有个api.php,这个是做接口使用的。区别是会去掉session cookie等相关中间件,路径上会自动添加/api前缀。这个目前也暂时不需要了解太多。后面的项目我们碰到做接口再细说了。