记录Laravel的一些基础知识…
原文地址: Head into Laravel
准备
全局安装 Composer
1 | curl -sS https://getcomposer.org/installer | php -- --install-dir=bin --filename=composer |
安装 Laravel
/Lumen
1 | composer global require laravel/installer |
自带服务器运行
1 | laravel new site |
注意
- 安装指定版本的
Laravel/Lumen
1 | composer create-project laravel/laravel blog "5.1.*" |
Blade
布局视图
1 | <!-- layouts/main.blade.php --> |
普通视图
1 | <!-- index.blade.php --> |
Data
将数据传递到视图
- 数组格式
1 | Route::get('/', function () { |
compact()
1 | Route::get('/', function () { |
with()
1 | Route::get('/', function () { |
- 动态方法
1 | Route::get('/', function () { |
数据库驱动
config/database.php
找到 'default' => env('DB_CONNECTION', 'mysql')
,修改成需要的驱动就可以了.
If use sqlite(file based database for small project), please comment the DB_* fields in
.env
file.
Migration
Migration: The Version Controll of Database
1 | # 1. define the table we want to create |
Tinker
你的项目的所有PHP laravel方法能够被执行在Tinker
1 | php artisan tinker |
命名空间等于文件夹结构。
命名空间
的回顾
在像PHP这样的编程语言中 命名空间用于放置类,避免类名相同时的歧义。
在laravel,定位的两种方法的类:
- use
use \Path\To\Class
; before the class defination. - use
\Classname
in the function block.
注意,当您不使用任何命名空间时,PHP将在当前命名空间中搜索您需要的类。
查询生成器
这是Laravel
一个传统与数据层交互方式。
Eloquent
: ORM of Laravel
简单地说,它只是MVC
设计模式中的M
层。
不同的是,它是在PHP的活动记录实现与数据库表进行交互,而不是使用传统的查询生成器。
其结果是,每个表有一个模型,模型代表表和表的增删改查选项更方便和愉快的模型。
在Laravel
中的使用步骤:
- 1.Create table via
make:migration
- 2.Insert data into the table
- 3.Make a Model reference to the table
1 | php artisan make:model Models/User -m # --migration |
- m
选项仅用于我们没有创建此模型响应的表时。
注意这里有一条规则:
Model name must be singular, but table name must be plurals.
模型名称必须是单数,但表名必须是复数。
For example, model name of table histories
should be history
.
- 4.Using Model in controller
For example, we have created a table users
, and a model User
in namespace App\Models\User
, contents of App\Http\routes.php
like these:
在路由中使用:
1 | Route::get('users', 'Users@index'); |
在控制器中使用:
1 |
|
- 5.Pass the result data to blade views when necessary
只需要注意: .
是连接/目录的意思, 比如 view(users.show)
意思是 resources/views/users/show.blade.php
Eloquent
举个简单的例子 我们创建表: users
, cards
, notes
1 | php artisan make:model Models\User -m |
我们所定义的每个up()
方法:
在
database/migrations/
CreateUsersTable:
1 | Schema::create('users', function (Blueprint $table) { |
CreateCardsTable:
1 | Schema::create('cards', function (Blueprint $table) { |
CreateNotesTable:
1 | Schema::create('notes', function (Blueprint $table) { |
显然, 他们之间的关系: user has cards
, cards has notes
. 测试前, 运行迁移:
1 | php artisan migrate |
Ok then. How to define the relationship with Eloquent are basically the same, so we take the cards has notes relationship to explain how it works.
好吧, 怎么使用Eloquent
关联模型基本一致, 所以我们就使用 cards
has notes
的关系来解释.
Get
/Query
No Eloquent
1 | php artisan tinker |
Yes, it just manually relate their relationship. It’s a little bit inelegant.
With Eloquent
- define the
notes()
method in Card Model
1
2
3
4
5
6
7
8
9
10public function notes()
{
return $this->hasMany(Note::class); // either `Note::class` or `\App\Models\Note`
}
public function path()
{
return '/cards/' . $this->id;
}当我们使用
\App\Models\Notes
将转化成对象, 使用Notes::class
将转化成类的字符串表示形式。- call the
notes()
method in Card Model instance
1
2
3
4
5
6
7
8
9
10
11php artisan tinker
$card = App\Models\Card::first()
$card->notes->first() # as collection
# Or
# $card->notes[0] # as array
# Or
# $card->notes()->first() # as object集合和对象的不同在于最后的查询
sql
通过一个测试证明下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35php artisan tinker # refresh the modifications in project
# Setup a listener when query event occurs
>>> DB::listen(function ($query){ echo $query->sql; }
>>> $card = new App\Models\Card::first()
select * from "cards" limit 1;
# First execute the get-card-notes query
>>> $card->notes
select * from "notes" where "notes"."card_id" = ? and "note"."card_id" is not null
# Re-execute the same query
>>> $card->notes
# You will see nothing here because the last query result is stored in the $card object and fetch them directly from object rather than the database
# Check if the $card object has the notes relationships here
>>> $card
# You will see the notes of this card here
# Check if notes relationship still exists after we refresh the object
>>> $card->fresh()
select * from "cards" where "id" = ? limit 1
>>> $card
# You wil note see the notes of this card here any more because the resuls cache are erased after `fresh()`
# If we use as collection, the sql of get first note record might be like this:
>>> $card->fresh()->notes->first()
select * from "cards" where "id" = ? limit 1
select * from "notes" where "notes"."card_id" = ? and "notes"."card_id" is not null
# If we use as object method, the sql of get first note record might be like this:
>>> $card->fresh()->notes()->first()
select * from "cards" where "id" = ? limit 1
select * from "notes" where "notes"."card_id" = ? and "notes"."card_id" is not null limit 1测试结果和上面的结论一致.
- define the
hasMany
and belongsTo
Moreover, we can say that note also belongs to card. So here is how eloquent deal with this
belongs-to
relationship here.
简单来说:就是 谁拥有谁==谁属于谁
- define the
card()
method in Note Model:
1
2
3
4public function card()
{
return $this->belongsTo(Card::class);
}- define the
- call the
card
method in Note Model instance
1
2
3
4
5php artisan tinker
- call the
Be aware that:
hasMany()
related method isnotes()
, which is resonable because one card can has many notes, andbelongsTo()
related method iscard()
, which is resonable because one note only belongs to one card.
注意到: hasMany()
对应的方法是 notes
(复数),是因为 一张卡可以有很多笔记, belongTo
对应的方法是 card()
(单数),是因为 一个笔记只属于一张卡
你不应该创建方法名为 note()
或 cards()
,因为它没有任何意义,必须回应你叫它什么方法。
记住,hasmany()
和复数的方法有关,belongsto()
和单数的方法相关。
Create
/save
1 | php artisan tinker |
Notice that here we didn’t set the card_id
for $note
, because eloquent automatically did this for us.
When we creating new record, we cann’t use collections any more, because it is only used for query-like operations.
此外,当我们通过 create()
直接创建一个新的记录, 需要某个字段批量赋值如:content
, 需要在$fillable
定义.
1 | class Note extends Model |
$fillable
可以作为设置被批量赋值的属性的「白名单」, 这也是Laravel
中避免攻击的方法之一.
Form
基于之前的例子:我们有 resources/views/cards/show.blade.php
1 | @extends('layouts.main') |
创建 routes.php
:
1 | Route::post('cards/{card}/notes', 'Notes@store'); |
创建控制器 Notes@store
:
1 | public function store(Request $request, Card $card) |
注意:
- If you want use eloquent as an instance, the param name
$card
must equals to the route catch name{card}
, herecard
equalscard
. Or$card
in method will be nothing, which is unexpected.
- If you want use eloquent as an instance, the param name
- When we use
create()
to insert an relationship, we must make sure that we had stipulated the$fillable
in related model, as we talked before.
- When we use
Since card and note has relationship here, so we can add a method to describle more clearer what we want to do, we can add a method addNote()
in model Card, like this:
1 | public function addNote(Note $note) |
最后, 控制器中 Notes@store()
:
1 | public function store(Request $request, Card $card) |
RESTful Principles Review
RESTful
接口整个说明本表:
此外,由于浏览器只直接理解GET
和POST
方法,所以遵循REST
约定可以像这样做:
Update
And Eager Loading
预先加载是避免大量的数据库查询该对象的数据可以得到一个查询通过建立laravel
模型关系的有效途径。
Before we using eager loading, if we want to get both the notes of one card, and the user this card belongs to, we may query N+1 times like this (
notes
table must has fileds named withuser_id
andcard_id
):
1 | public function showByInstance(Card $card) |
这里需要查询两次, 这是低效的
使用预加载,我们可以将两次查询合并成一次,就像:
1 | public function showByInstance(Card $card) |
Validation
Form input
1 | public function addNote(Request $request, Card $card) |
CSRF
: See detail in FAQ.
Middleware
1 | Route::group([ |
Errors
每个视图都可以共享($errors)错误变量。
old('field_name')
When form check fails, the preview wrong data are
withInput()
in the redirect, and we can put it into the right elements.
通过 old()
,获取上一次输入的内容.
FAQ
1 | composer dump-autoload |
1 | PUT = replace the ENTIRE RESOURCE with the new representation provided (no mention of related resources in the spec from what i can see) |
重置和刷新命令列表
php artisan clear-compiled
: 删除已编译的类文件php artisan auth:clear-resets
: 刷新过期密码重置令牌php artisan cache:clear
: 刷新应用程序缓存php artisan config:clear
: 删除配置缓存文件php artisan migrate:refresh
: 重置并重新运行所有迁移
Same with migrate:rollback
, they will erase the data in database.
php artisan migrate:reset
: 回滚所有数据库迁移php artisan queue:flush
: 刷新所有失败的队列作业php artisan queue:forget
: 删除失败的队列作业php artisan route:clear
: 删除路由缓存文件php artisan view clear
: 清除所有的编译文件