一.路由(https://d.laravel-china.org/docs/5.5/routing)
路由形式
1.闭包形式
Route::get('foo', function () {
return 'Hello World';
});
2基本模式
Route::get/post/put/delete('/user', 'UsersController@index');
匹配多种请求方式
可以通过match字段匹配多个请求方式
Route::match(['get', 'post'], '/', function () {
//
});
any匹配任何方式
Route::any('foo', function () {
//
});
POST、PUT 或 DELETE请求方式必须包含CSRF 令牌 否则被拒绝
3重定向路由
Route::redirect('/here', '/there', 301);
4视图路由
它和 redirect 一样方便,不需要定义完整的路由或控制器。view 方法有三个参数,其中前两个是必填参数,分别是 URL 和视图名称。第三个参数选填,可以传入一个数组,数组中的数据会被传递给视图。
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
路由参数(参数写在{}里,只能采用字母下划线命名)
必填参数
Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
//
});
可选参数(在参数后加?符号,确保其有默认值)
Route::get('user/{name?}', function ($name = 'John') {
return $name;
});
后面加where可以约束参数值的类型
Route::get('user/{id}', function ($id) {
//
})->where('id', '[0-9]+');
参数的全局约束(应用于该参数所有的路由)
使用 pattern 方法在 RouteServiceProvider 的 boot 方法中定义这些模式:
/**
* 定义你的路由模型绑定, pattern 过滤器等。
*
* @return void
*/
public function boot()
{
Route::pattern('id', '[0-9]+');
parent::boot();
}
路由命名
命名路由可以方便地为指定路由生成 URL 或者重定向。通过在路由定义上链式调用 name 方法指定路由名称:
Route::get('user/profile', function () {
//
})->name('profile');
你还可以指定控制器行为的路由名称:
Route::get('user/profile', 'UserController@showProfile')->name('profile');
定义路由命名后 或许可以再传入参数
Route::get('user/{id}/profile', function ($id) {
//
})->name('profile');
$url = route('profile', ['id' => 1]);
判断请求是否指向某个路由
if ($request->route()->named('profile')) {
//
}
路由组
1中间件 要给路由组中所有的路由分配中间件,可以在 group 之前调用 middleware 方法.中间件会依照它们在数组中列出的顺序来运行
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// 使用 first 和 second 中间件
});
Route::get('user/profile', function () {
// 使用 first 和 second 中间件
});
});
2路由命名空间
另一个常见用例是使用 namespace 方法将相同的 PHP 命名空间分配给路由组的中所有的控制器:
Route::namespace('Admin')->group(function () {
// 在 "App\Http\Controllers\Admin" 命名空间下的控制器
});
请记住,默认情况下,RouteServiceProvider 会在命名空间组中引入你的路由文件,让你不用指定完整的 App\Http\Controllers 命名空间前缀就能注册控制器路由。因此,你只需要指定命名空间 App\Http\Controllers 之后的部分。
二 中间件(lavarel采用中间件过滤HTTP请求)
Laravel 自带了一些中间件,包括身份验证、CSRF 保护等。所有这些中间件都位于 app/Http/Middleware 目录。
也可以自定义中间件
创建新的中间件:php artisan make:middleware CheckAge
该命令将会在 app/Http/Middleware 目录内新建一个 CheckAge 类。在这个中间件里,我们仅允许提供的参数 age 大于 200 的请求访问该路由。否则,我们会将用户重定向到 home
namespace App\Http\Middleware;
use Closure;
class CheckAge
{
/**
* 处理传入的请求
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->age <= 200) {
return redirect('home');
}
return $next($request);
}
}
如你所见,若给定的 age 小于等于 200,那中间件将返回一个 HTTP 重定向到客户端;否则,请求将进一步传递到应用中。要让请求继续传递到应用程序中(即允许「通过」中间件验证的),只需使用 $request 作为参数去调用回调函数 $next
中间件是在请求之前或之后运行取决于中间件本身。例如,以下的中间件会在应用处理请求 之前 执行一些任务
三. CSRF
Laravel 会自动为每个活跃用户的会话生成一个 CSRF「令牌」。该令牌用于验证经过身份验证的用户是否是向应用程序发出请求的用户
可以添加白名单 设置不需CSRF保护的url
可以把这类路由放到 routes/web.php 外,因为 RouteServiceProvider 的 web 中间件适用于该文件中的所有路由。不过,你也可以通过将这类 URI 添加到 VerifyCsrfToken 中间件中的 $except 属性来排除对这类路由的 CSRF 保护
class VerifyCsrfToken extends BaseVerifier
{
/**
* 这些 URI 将免受 CSRF 验证
*
* @var array
*/
protected $except = [
'stripe/*',
];
}
除了检查 POST 参数中的 CSRF 令牌外,VerifyCsrfToken 中间件还会检查 X-CSRF-TOKEN 请求头。你可以将令牌保存在 HTML meta 标签中:
"csrf-token" content="{{ csrf_token() }}">
然后你就可以使用类似 jQuery 的库自动将令牌添加到所有请求的头信息中。这可以为基于 AJAX 的应用提供简单、方便的 CSRF 保护:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
四 请求
获取参数
1依赖注入的方式
public function store(Request $request)
{
$name = $request->input('name');
//
}
2从路由中获取
public function update(Request $request, $id)
{
//
}
获取url
// Without Query String...
$url = $request->url();
// With Query String...
$url = $request->fullUrl();
获取请求路径
$uri = $request->path();
获取判断方法
$method = $request->method();
if ($request->isMethod('post')) {
//
}
五.响应
response()->
六.视图
Route::get('/', function () {
return view('greeting', ['name' => 'James']);
});
return view('greeting')->with('name', 'Victoria');
与所有视图共享数据
在服务提供器的 boot 方法中调用视图 Facade 的 share 方法。例如,可以将它们添加到 AppServiceProvider 或者为它们生成一个单独的服务提供器
七.验证
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
在第一次验证失败后停止
$this->validate($request, [
'title' => 'bail|required|unique:posts|max:255',
'body' => 'required',
]);
在这个例子里,如果 title 字段没有通过 unique,那么不会检查 max 规则。规则会按照分配的顺序来验证。
数组参数的验证,通过. 指向数组中的key的值
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);
我们不必在 GET 路由中将错误消息显式绑定到视图。因为 Lavarel 会检查在 Session 数据中的错误信息,并自动将其绑定到视图(如果存在)。而其中的变量 $errors 是 Illuminate\Support\MessageBag 的一个实例。要获取关于这个对象的更多信息,请 查阅这个文档。
$errors 变量被由Web中间件组提供的 Illuminate\View\Middleware\ShareErrorsFromSession 中间件绑定到视图。当这个中间件被应用后,在你的视图中就可以获取到 $error 变量,可以使一直假定 $errors 变量存在并且可以安全地使用。
表单请求类(适应更为复杂的验证)
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
错误信息
public function messages()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
数据库
1.原生Sql查询
$users = DB::select('select * from users where active = ?', [1]);
$affected = DB::update('update users set votes = 100 where name = ?', ['John']);
2.查询构造器
$users = DB::table('users')->get();
$user = DB::table('users')->where('name', 'John')->first();
获取特定字段的值(采用pluck)
$roles = DB::table('roles')->pluck('title', 'name');
分块取出(chunk)
DB::table('users')->orderBy('id')->chunk(100, function ($users) {
foreach ($users as $user) {
//
}
});
return false 停止后续分块查询
DB::table('users')->orderBy('id')->chunk(100, function ($users) {
// Process the records...
return false;
});
链式方法后面可以直接跟聚合查询
count、 max、 min、 avg 和 sum
$price = DB::table('orders')->max('price');
$price = DB::table('orders')
->where('finalized', 1)
->avg('price');
只查询需要的字段对比(chunk)
$users = DB::table('users')->select('name', 'email as user_email')->get();
去重
$users = DB::table('users')->distinct()->get();
从已知的构造查询器中增加查询的字段
$query = DB::table('users')->select('name');
$users = $query->addSelect('age')->get();
关联查询
1.inner join
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();
2.left join
$users = DB::table('users')
->leftJoin('posts', 'users.id', '=', 'posts.user_id')
->get()
3.闭包形式的join用法
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')->orOn(...);
})
->get();
常见链式方法
引用块内容
where or whereBetween whereNotBetween
whereIn whereNotIn whereNull whereNotNull
whereDate / whereMonth / whereDay / whereYear
whereColumn Where Exists
DB::table('users')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
select * from users
where exists (
select 1 from orders where orders.user_id = users.id
)
orderBy latest / oldest inRandomOrder
groupBy / having / havingRaw
skip / take
你可以使用 skip 和 take 方法来限制查询结果数量或略过指定数量的查询:
$users = DB::table('users')->skip(10)->take(5)->get();
或者,你也可以使用 limit 和 offset 方法:
$users = DB::table('users')
->offset(10)
->limit(5)
->get();
当条件成立时才执行查询(when)
$users = DB::table('users')
->when($sortBy, function ($query) use ($sortBy) {
return $query->orderBy($sortBy);
}, function ($query) {
return $query->orderBy('name');
})
->get();
插入
DB::table('users')->insert([
['email' => '[email protected]', 'votes' => 0],
['email' => '[email protected]', 'votes' => 0]
]);
插入数据并且获取其自增Id(insertGetId)
$id = DB::table('users')->insertGetId(
['email' => '[email protected]', 'votes' => 0]
);
Upload
DB::table('users')
->where('id', 1)
->update(['votes' => 1]);
DB::table('users')->increment('votes', 5);
DB::table('users')->decrement('votes');
可以在自增的同时 更新其他字段
DB::table('users')->increment('votes', 1, ['name' => 'John']);
delete
DB::table('users')->delete();
DB::table('users')->where('votes', '>', 100)->delete();
清空表
DB::table('users')->truncate();
悲观锁?what
查询构造器也包含一些可以帮助你在 select 语法上实现「悲观锁定」的函数 。若要在查询中使用「共享锁」,可以使用 sharedLock 方法。共享锁可防止选中的数据列被篡改,直到事务被提交为止:
分页
查询构造器分页
每页15条
$users = DB::table('users')->paginate(15);
仅支持上一页下一页
$users = DB::table('users')->simplePaginate(15);
Laravel无法有效执行使用 groupBy 语句的分页操作。如果你需要在一个分页结果集中使用 groupBy,建议你查询数据库并手动创建分页器
模型
1.自动生成模型
命令:php artisan make:model User
顺便生成数据库迁移
php artisan make:model User --migration
php artisan make:model User -m
class Flight extends Model
{
/**
* 与模型关联的数据表
*
* @var string
*/
protected $table = 'my_flights';//该模型对应Flight表 如果不写则默认对应Flights表
}
主键
Eloquent 也会假设每个数据表都有一个叫做 id 的主键字段。你也可以定义一个 $primaryKey 属性来重写这个约定。此外,Eloquent 假定主键是一个递增的整数值,这意味着在默认情况下主键将自动的被强制转换为 int。 如果你想使用非递增或者非数字的主键,你必须在你的模型 public $incrementing 属性设置为false
时间戳
默认情况下,Eloquent 会认为在你的数据库表有 created_at 和 updated_at 字段。如果你不希望让 Eloquent 来自动维护这两个字段,可在模型内将 $timestamps 属性设置为 false
数据库连接
默认情况下,所有的 Eloquent 模型会使用应用程序中默认的数据库连接设置。如果你想为模型指定不同的连接,可以使用 $connection 属性
protected $connection = 'connection-name';
模型查询
$flights = App\Flight::all();
$flights = App\Flight::where('active', 1)
->orderBy('name', 'desc')
->take(10)
->get();
由于 Eloquent 模型是查询构造器,因此你应当去阅读 查询构造器 中所有可用的方法。你可在 Eloquent 查询中使用这其中的任何方法
分块处理,类似查询构造器中的chunk,这里采用闭包模式
Flight::chunk(200, function ($flights) {
foreach ($flights as $flight) {
//
}
});
取回单个模型/集合
// 通过主键取回一个模型...
$flight = App\Flight::find(1);
$flights = App\Flight::find([1, 2, 3]);
// 取回符合查询限制的第一个模型 ...
$flight = App\Flight::where('active', 1)->first();
为查询到结果自动返回异常
$model = App\Flight::where('legs', '>', 100)->firstOrFail();
聚合
可以使用查询构造器中的聚合函数count、sum、max...
$count = App\Flight::where('active', 1)->count();
$max = App\Flight::where('active', 1)->max('price');
新增模型记录
基本添加
要在数据库中创建一条新记录,只需创建一个新模型实例,并在模型上设置属性和调用 save 方法即可:
public function store(Request $request)
{
// 验证请求...
$flight = new Flight;
$flight->name = $request->name;
$flight->save();
}
save 方法被调用时,created_at 以及 updated_at 时间戳将会被自动设置,因此我们不需要去手动设置它们。
基本更新
要更新模型,则须先取回模型,再设置任何你希望更新的属性,接着调用 save 方法。同样的,updated_at 时间戳将会被自动更新,所以我们不需要手动设置它的值:
$flight = App\Flight::find(1);
$flight->name = 'New Flight Name';
$flight->save();
批量更新
App\Flight::where('active', 1)
->where('destination', 'San Diego')
->update(['delayed' => 1]);
创建或者更新模型
其次,你可能会碰到模型已经存在则更新,否则创建新模型的情形,Laravel 提供了一个 updateOrCreate 方法来一步完成该操作,类似 firstOrCreate 方法, updateOrCreate 方法会持久化模型,所以无需调用 save() :
$flight = App\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99]
);
删除
基本删除
$flight = App\Flight::find(1);
$flight->delete();
通过主键删除
App\Flight::destroy(1);
App\Flight::destroy([1, 2, 3]);
App\Flight::destroy(1, 2, 3);
删除多个
$deletedRows = App\Flight::where('active', 0)->delete();
软删除
必须在模型上使用 Illuminate\Database\Eloquent\SoftDeletes trait 并添加 deleted_at 字段到你的 $dates 属性上:
class Flight extends Model
{
use SoftDeletes;
/**
* 需要被转换成日期的属性。
*
* @var array
*/
protected $dates = ['deleted_at'];
}
当然,你也应该添加 deleted_at 字段到数据表中。Laravel 结构生成器 包含了一个用来创建此字段的辅助函数:
Schema::table('flights', function ($table) {
$table->softDeletes();
});
正常的查询中软删除的字段是不会被查出的,但是可以通过如下方法查询
$flight->history()->withTrashed()->get();//其他字段也查询出
只查询出删除的字段
$flights = App\Flight::onlyTrashed()
->where('airline_id', 1)
->get();
把软删除的数据恢复
$flight->restore();
App\Flight::withTrashed()
->where('airline_id', 1)
->restore();
永久删除软删除
// 强制删除单个模型实例...
$flight->forceDelete();
// 强制删除所有相关模型...
$flight->history()->forceDelete();
关联模型
一对一
public function user()
{
return $this->belongsTo('App\User');
}
return $this->hasOne('App\Phone', 'foreign_key');
一对多
public function comments()
{
return $this->hasMany('App\Comment');
}
public function post()
{
return $this->belongsTo('App\Post');
}