Laravel学习笔记

这篇博客详细介绍了Laravel框架的基础功能,包括路由、控制器、请求处理、URL生成、Cookie和Session管理。深入探讨了Blade模板、数据库操作、ORM(对象关系映射)以及表单验证。此外,还讲解了CSRF保护、中间件的创建和使用,以及前端开发中的Blade模板和视图。内容涵盖从基础到进阶,适合Laravel初学者和开发者参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基础功能

路由
  • 对路由参数约束限制
Route::get('task/read/{id}', 'TaskController@read')
->where('id', '[0-9]+'); //单个参数
->where(['id'=>'[0-9]+', 'name'=>'[a-z]+']); //多个参数
  • 路由重定向
Route::redirect('index', 'task');
Route::redirect('index', 'task', 301); //状态码

前提是先定义好了task路由!
还有一个方法,可以直接让路由跳转返回 301 状态码而不用设置:

Route::permanentRedirect('index', 'task');

使用 redirect()助手结合 route()生成一个重定向跳转,

//生成重定向
return redirect()->route('task.index', ['id'=>10]);
  • 路由分组
    1 设置子域名,从而限定路由可执行的域名
Route::domain('localhost')->group(function (){
    Route::get('read','TaskController@read')->name('read');
    Route::get('index','TaskController@index');
});
这样,之前访问的http://127.0.0.1:8000/read就无法再访问,而是要访问http://localhost:8000/read
  • 路由回退
    可以使用回退路由,让不存在的路由自动跳转到你指定的页面去;
    注意:由于执行顺序问题,必须把回退路由放在所有路由的最底部;
Route::fallback(function () {
return redirect('/');
});

2 设置命名空间

Route::namespace('Admin')->group(function () {});

PS:在 Controller 目录下创建 Admin 目录,再其目录下创建的控制器AdminController.php,其命名空间如下:

namespace App\Http\Controllers\Admin;
  • 视图路由
    常用的是将路由直接指向控制器,通过方法实现 view()引入视图;
    public function index()
    {
    return view(‘task’, [‘id’=>10]);
    }
控制器
  • 使用命令生成一个:
php artisan make:controller TaskController
(切换到项目根目录下执行此命令)

生成的控制器目录在 app\Http\Controllers 下

  • 资源控制器
1. 生成资源控制器
php artisan make:controller BlogController --resource

2. 注册资源路由
Route::resource('blogs', 'BlogController'); //单个资源路由
//或者批量定义资源路由
Route::resources([
'blogs' => 'BlogController'
]);

在这里插入图片描述
如果我们注册了资源路由,那么如上图的资源路由 URI 和名称均自动创建生效;

请求和依赖注入
  • Request 请求
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController
{
//方法会自动得到 Request 对象,这个就是注入
public function index(Request $request)
{
//input 的方法可以获取 http 请求的数据
//localhost:8000/user?name=Mr.Lee
//参数 2 为默认值
$request->input('name', 'no name');

数组/JSON接收方式
return $request->input('select.1.b');

//动态方式获取
$request->name;

使用 all/input()方法,可以获取所有 url 传递过来的参数;
//http://localhost:8000/user?name=Mr.Lee&gender=&age=100
return $request->all();
}

路由自带参数时,可以通过第二,第三参数接受;
Route::get('/user/{id}/{uid}', 'UserController@index');
public function index(Request $request, $id, $uid)

5. 路由区域,也支持闭包注入 Request;
Route::get('/user', function (Request $request) {
return $request->all();
});

6. 使用 path()方法,可以得到当前的 uri 路径;
return $request->path();

7. 使用 is()方法,可以判断当前的 uri 是否匹配;
//是否是 user/*的 uri,返回布尔值
return $request->is('user/*');

8. 使用 url()和 fullUrl()得到 url 地址,带参数和不带参数区别;
return $request->url();
return $request->fullUrl();

9. 使用 isMethod()来判断 HTTP 请求的方式,get、post 等等;
return $request->isMethod('post');

}
  • 其他请求的常用方法
//返回布尔值
$request->boolean('name');
//返回 IP
$request->ip();
//只接受固定参数
$request->only(['age', 'gender']);
//排除不要的参数
$request->except(['name']);
//判断参数是否存在
return $request->has('name');
//判断参数是否全部存在
return $request->has(['name', 'age']);
//判断参数只有一个存在,就返回 true
return $request->hasAny(['name', 'age']);
//判断参数存在,并且不为空
return $request->filled('name');
//判断参数不存在(为空也不行)
return $request->missing('name');
  • request()助手函数,使用如下:
return request()->input();
生成URL
//生成指定的 url
$user = User::find(19);
return url('/user/'.$user->id);

如果 url()不给参数,可以当作对象执行更多的方法;
//得到当前 url,不带参数
return url()->current();
//得到当前 url,带参数
return url()->full();
//得到上一个 url
return url()->previous(); //URL::previous()

使用 route()方法,生成命名路由的 url,
Route::any('/url/{id}','UserController@url')->name('url.id');
return route('url.id', ['id'=>5]);

//使用控制器返回 url(经测试,index方法需要在路由中注册后,下面代码才能正常执行)
return action('UserController@index', ['id'=>5]);

生成一个签名 URL,在 URL 后面追加一个哈希签名字符串,用于验证;

return url()->signedRoute('url.id', ['id' => 5]);//这里url.id为设置的路由别名,也就是路由的name
//验证哈希签名
return request()->hasValidSignature()
COOKIE
  1. 首先,获取 Cookie 有两种方法,具体如下:
//注意 Laravel 中 cookie 都是加密的,原生 cookie 只能获取加密信息
//使用 request()->cookie 获取解密后的 cookie 信息
return request()->cookie('laravel_session');
//使用 Cookie::也可以获取,引入 Illuminate\Support\Facades\Cookie;
return Cookie::get('laravel_session');

新增

Cookie::queue('age', 100, 10);
SESSION
  1. 获取
//获取 session 值
return session('_token');
//获取 session 值并设置默认值
return session('name', 'no session name');
  1. 判断
return Session::has('name'); //判断是否存在且不为 null
return Session::exists('name'); //判断是否存在,即使是 null也判为存在
  1. 增加
//设置 session 值
session(['name' => 'Mr.Lee']);
//也支持 request()存储
Session::put('name', 'MrWang');

使用 push()方法,可以存储数组,
Session::push('info.name', 'Mr.Lee');
Session::push('info.name', 'Mr.Wang');
Session::push('info.name', 'Mr.Zhang');
return Session::get('info');

//存储的 session 只能被获取一次,然后自动删除,flash 也称为闪存数据
Session::flash('name', 'Mr.Lee');

如果使用闪存数据,本次请求不要立刻自行删除,可以使用 reflash();
//本次请求获取,不要删除数据,给下一次请求时再自行删除,这是保存所有闪存数据
Session::reflash(); //Session::keep(['name']);保存单独的闪存数据
return Session::get('name');
  1. 删除
//删除一条数据
Session::forget('name'); 
return Session::get('name');
//删除多条数据
Session::forget(['name'])
//删除一条数据,并返回
Session::pull('info');
//删除所有数据
Session::flush();
  1. session ID
//重新生成 SessionID
Session::regenerate();
//获取 SessionID
return Cookie::get('laravel_session');
中间件

中间件就是当程序接收 HTTP 请求时,拦截后进行过滤和处理。

  1. 创建
php artisan make:middleware Check

生成Http/Middleware/Check.php

修改此文件:

//固定方法,固定格式
public function handle($request, Closure $next)
{
//这里编写验证跳转方法
if ($request->get('id') != 1) {
return redirect(url('/login'));
}
//固定返回格式,让其继续往下执行
return $next($request);
}
  1. 注册
    打开 Http/Kernel.php,
    protected $middleware是注册全局中间件,每次执行都必然调用。不需要步骤3.
    protected $routeMiddleware为路由配置中间件。
    例如在路由配置中间件住注册上述的check中间件:
protected $routeMiddleware = [
'check'=>\App\Http\Middleware\Check::class,
]
  1. 使用
Route::get('/admin','LoginController@index')->middleware('check');

//设置多个中间件
->middleware('check', 'auth');

//或者没有在 Http/Kernel.php中注册中间件,直接采用完整的类名来进行调用:
->middleware(\App\Http\Middleware\Check::class);

  1. 参数
//传参
->middleware('check:abc');
//$param
public function handle($request, Closure $next, $param)
  1. 中间件组
protected $middlewareGroups = [
'mymd' => ['check'=>\App\Http\Middleware\Check::class,]
];
  1. 中间件的 terminate()方法,可以在中间件响应完之后也就是(return $next)之后再调用;
//Http/Middleware/Check.php
public function terminate($request, $response)
{
echo '<br>Http 响应完毕之后再调用我';
}
表单验证
  1. 创建验证类
php artisan make:request Form

//Http\Request\Form.php
public function authorize()
{
//默认 false,为关闭授权,关闭状态会 403
//比如判断这个用户是否有操作权限
return true;
}
public function rules()
{
return [
//规则
'username' => 'required|min:2|max:10',
'password' => 'required|min:6',
];
}
//设置中文提示
public function messages()
{
return [
'username.required' => '用户名不得为空~',
'username.min' => '用户名不得小于 2 位~',
'username.max' => '用户名不得大于 10 位~',
'password.required' => '密码不得为空~',
'password.min' => '密码不得小于 6 位~',
];
}

如果验证没有被通过,会自动重定向到提交页。
2. 在控制器中使用

public function index(Form $request)
    {
        $request->validated();
    }

CSRF保护

  • CSRF保护,在表单页面添加@csrf
  • 表单伪造提交方式,在表单页面添加@method('PUT')
  • 如果我们想让某些 URL 关闭 csrf 验证,可以设置 csrf 白名单;
    在VerifyCsrfToken 中间件里,添加白名单,如下所示:
  protected $except = [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ];

前端开发

Blade 模板
  1. 目录:resources/views ,
    后缀:.blade.php;
  2. 模板基础功能
  • 传递变量
//参数 2 数组,声明模板变量
return view('user', [
'name' => 'Mr.Lee' //{{$name}} 在模板使用变量
]);
  • 路由直接加载模板
Route::get('/task/user', function () {
return view('user', [
'name' => 'Mr.Lee'
]);
});
  • 子目录的调用方式
//resources/views/admin/index.blade.php
return view('admin.index');
  • 判断模板文件是否存在
return view()->exists('admin.index');
  • 加载数组中的首个存在的模板
return view()->first(['abc', 'user', 'def'], [
'name' => 'Mr.Lee'
]);
模版的流程控制
  1. 条件判断
@if($num > 10)
num 大于 10
@elseif($num > 5)
num 大于 5
@else
num 小于 5
@endif


@isset 判断变量是否存在 @empty 判断变量是否为空;
@isset($name)
变量存在
@endisset
@empty($name)
变量为空
@endempty

@switch($num)
@case(1)
1
@break
@case(4)
4
@break
@default
不存在
@endswitch
  1. 循环遍历
3. @for 循环,适合数值的循环;
@for($i =0; $i <= 10; $i++)
{{$i}}
@endfor

4. @foreach 适合对象的变量循环;
@foreach($obj as $user)
{{$user->username}}
@endforeach

5. @continue 可以跳出当且迭代,@break 跳出循环;
@foreach($obj as $user)
@if ($user->username == '樱桃小丸子')
@continue //@break
@endif
{{$user->username}}
@endforeach
PS:变体写法:@continue($user->username == '樱桃小丸子')

6. @white 判断循环;
@while($num > 0)
while 循环
{{$num--}}
@endwhile

7. 在循环体内,会有一个@loop 变量,帮助我们处理各种问题;
@foreach($obj as $user)
@if($loop->first)
[起始数据之前]
@endif
@if($loop->last)
[末尾数据之前]
@endif
{{$user->username}} --
@endforeach

在这里插入图片描述
3. 模板的继承布局

  • 其它技巧
1. 默认变量会被自动转义,比如特殊符号&,如果不想被转义可以用如下格式:
{!! $name !!}

2. 可以使用@json 直接将数组转换成 json 格式,参数 2 格式化,和原生一样;
@json($list)
@json($list, JSON_PRETTY_PRINT)

3. 在 JavaScript 区域,可能也有{{name}}这种模式的操作,和模版变量冲突;
{{--加上@即可防止解析--}}
@{{ name }}
{{--大量 JS 时,用范围方式--}}
@verbatim
{{ name }}
@endverbatim

数据库

查询构造器
  • 常用查询
1. 
//获取全部结果
$users = DB::table('users')->get();
2. 
//获取第一条数据
$users = DB::table('users')->first();
3. 
//获取第一条数据的 email 字段值
$users = DB::table('users')->value('email');
4. 
//通过 id 获取指定一条数据
$users = DB::table('users')->find(20);
find([1,2,3]) //通过数组查找
5. 
//获取单列值的集合
$users = DB::table('users')->pluck('username');
$users = DB::table('users')->pluck('username', 'email');
6. 
//直接使用 selectRaw()方法实现原生
$users = DB::table('users')->selectRaw('COUNT(*) AS count, gender')
->groupBy('gender')
->get();
7. 
//使用 havingRaw 方法实现分组筛选
$users = DB::table('users')->selectRaw('COUNT(*) AS count, gender')
->groupBy('gender')
->havingRaw('count>5')
->get();
8. where 查询
//where 查询完整形式
$users = DB::table('users')->where('id', '=', 19)->get();
当然,还有><>=<=<>、like 等操作符;
users = DB::table('users')->where('price', '>=', 95)->get();
$users = DB::table('users')->where('username', 'like', '%小%')->get();
//多条件
//如果条件都是等于、
$users = DB::table('users')->where([
'price' => 90,
'gender' => '男'
])->get();
//如果条件非等于
$users = DB::table('users')->where([
['price', '>=', 90],
['gender', '=', '男']
])->get();

////where() + Where 实现 and 条件查询
//where() + orWhere 实现 or 条件查询
$users = DB::table('users')
->where('price', '>', 95)
->orWhere('gender', '女')
->toSql();

通过闭包,我们还可以构建更加复杂的 orWhere 查询;
//orWhere()结合闭包查询
$users = DB::table('users')
->where('price', '>', '95')
->orWhere(function ($query) {
$query->where('gender', '女')
->where('username', 'like', '%小%');
})->toSql();

whereBetween()可以实现区间查询,比如价格在一个区间内的用户;
//whereBetween 查询区间价格 60~90 之间
$users = DB::table('users')->whereBetween('price', [60, 90])->toSql();
PS:这里还支持相关三种:whereNotBetween/orWhereBetween/orWhereNotBetween;

whereIn()可以实现数组匹配查询,比如匹配出数组里指定的数据;
//whereIn 查询数组里匹配的数值
$users = DB::table('users')->whereIn('id', [20,30,50])->toSql();
PS:这里还支持相关三种:whereNotIn/orWhereIn/orWhereNotIn;

//whereNull 查询字段值为 Null 的记录
$users = DB::table('users')->whereNull('uid')->toSql();
PS:这里还支持相关三种:whereNotNull/orWhereNull/orWhereNotNull;

whereDate()可以查询指定日期的记录;
//whereYear 查询指定日期的记录,或大于
$users = DB::table('users')->whereDate('create_time', '2018-12-11')->toSql();
PS:这里还支持相关四种:whereYear/whereMonth/whereDay/whereTime,支持 or 前缀;
PS:三个参数支持大于小于之类的操作 orWhereDate('create_time','>', '2018-12-11')


使用 whereColumn()方法实现两个字段相等的查询结果;
//判断两个相等的字段,同样支持 orWhereColumn()
//支持符号'create_time','>', 'update_time'
//支持符号支持数组多个字段格式['create_time','>', 'update_time']
$users = DB::table('users')
->whereColumn('create_time', 'update_time')
->get();

使用 latest()方法设置时间倒序来排,默认时间字段是 created_at;
//按照创建时间倒序排,默认字段 created_at
$users = DB::table('users')->latest('create_time')->toSql();

//随机排序
$users = DB::table('users')->inRandomOrder()->get();

//从第 3 条开始,显示 3 条
$users = DB::table('users')->skip(2)->take(3)->toSql();
$users = DB::table('users')->offset(2)->limit(3)->get();

//when 实现条件选择
$users = DB::table('users')->when(true, function ($query) {//when第一个参数为true时,执行第一个闭包函数,为false执行第二个
$query->where('id', 19);
}, function ($query) {
$query->where('username', '辉夜');
})->get();

如果 MySQL 在 5.7+,有支持 JSON 数据的新特性;
$users = DB::table('users')->where('list->id', 19)->first();
//新增时,转换为 json 数据
'list' => json_encode(['id'=>19])
//修改时,使用 list->id 指定
DB::table('users')->where('id', 306)
->update([
'list->id' => 20
]);

子查询
1. 使用 whereExists()方法实现一个子查询结果,返回相应的主查询;
//通过 books 表数据,查询到 users 表关联的所有用户
$users = DB::table('users')->whereExists(function ($query) {
$query->selectRaw(1)
->from('books')
->whereRaw('laravel_books.user_id = laravel_users.id');
})->toSql();

//whereRaw 这句也可以替代为:whereColumn('books.user_id','users.id');
PS:select 1 from,一般用于子查询的手段,目的是减少开销,提升效率,深入请搜索;

2. 也可以使用 where(字段,function())闭包,来实现一个子查询;
//id=子查询返回的 user_id
$users = DB::table('users')->where('id', function ($query) {
$query->select('user_id')
->from('books')
->whereColumn('books.user_id','users.id');
})->toSql();


join查询

1. 使用 join 实现内联接的多表查询,比如三张表进行 inner join 查询;
$users = DB::table('users')
->join('books', 'users.id', '=', 'books.user_id')
->join('profiles', 'users.id', '=', 'profiles.user_id')
->select('users.id', 'users.username', 'users.email',
'books.title', 'profiles.hobby')
->get();

2. 也可以使用 leftjoin 左连接或 rightjoin 右连接实现多表查询;
$users = DB::table('users')
->leftJoin('books', 'users.id', '=', 'books.user_id')
->rightjoin('profiles', 'users.id', '=', 'profiles.user_id')
->get();

3. 使用 crossjoin 交叉连接查询,会生成笛卡尔积,再用 distinct()取消重复;
$users = DB::table('users')
->crossJoin('books')
->select('username', 'email')
->distinct()
->get();

4. 如果你想要实现闭包查询,和 where 类似,只不过要用 on 和 orOn 方法;
$users = DB::table('users')
->join('books', function ($join) {
//支持 orOn 连缀
$join->on('users.id', '=', 'books.user_id');
})->toSql();
PS:on()方法后面如果想要再增加筛选条件,可以追加 where();

5. 使用 joinSub 实现子连接查询,将对应的内容合并在一起输出;
//子连接查询
$query = DB::table('books')->selectRaw('user_id,title');
$users = DB::table('users')->joinSub($query,'books', function ($join) {
$join->on('users.id', '=', 'books.user_id');
})->get();

6. 使用 union()或 unionAll()方法实现两个查询的合并操作;
//union 取消重复,unionAll 不取消重复
$query = DB::table('users');
$users = DB::table('users')
->union($query)
->get();


使用 insert()方法可以新增一条或多条记录;
//新增一条记录
DB::table('users')->insert([
'username' => '李白',
'password' => '123456',
'email' => 'libai@163.com',
'details' => '123'
]);
//新增多条记录
DB::table('users')->insert([
[...],
[...]
]);

//获取新增后返回的 ID
$id = DB::table('users')->insertGetId([
'username' => '李白',
'password' => '123456',
'email' => 'libai@163.com',
'details' => '123'
]);
return $id;

//更新修改一条数据
DB::table('users')->where('id', 304)
->update([
'username' => '李红',
'email' => 'lihong@163.com'
]);

//默认自增/自减为 1,可设置
DB::table('users')->where('id', 306)->increment('price');
DB::table('users')->where('id', 306)->increment('price', 2);

删除一条记录
DB::table('users')->delete(307);
删除多条记录
DB::table('users')->where('id', 307)->delete();

查看 SQL 语句用->toSql()替换->get()

  • 分块
    如果你一次性处理成千上万条记录,防止读取出错,可以使用 chunk()方法;
//切割分块执行,每次读取 3 条,id 排序;
DB::table('users')->orderBy('id')->chunk(3, function ($users) {
foreach ($users as $user) {
echo $user->username;
}
echo '------<br>';
});

ORM

默认设置

使用命令在 Http 目录下创建模型;

php artisan make:model Http/Models/User //默认在 app 目录

强制使用现有的数据表名;

protected $table = 'user';

系统假定你的主键为 id,如果你要修改默认主键,可以特定;

protected $primaryKey = 'xid';

系统假定你的主键 id 为自增性,意味着是主键会自动转换 int 类型
. 如果你希望不是非自增,非数值类型主键,可以设置取消;

public $incrementing = false;

如果你主键不是一个整数,那么需要$keyType 设置为 string;

protected $keyType = 'string';

系统默认情况下会接管 created_at 和 updated_at 两个时间戳列,新增、修改字段时不用管这两列;
如果不想让系统干涉这两个列,可以设置 false 取消;

public $timestamps = false;

可以更改创建时间 created_at 和更新时间 updated_at 字段名;

const CREATED_AT = 'create_time';
const UPDATED_AT = 'update_time';

如果你想自定义时间戳的格式,可以设置;

protected $dateFormat = 'U';

默认读取 config/database.php 配置的数据库连接,也可以在模型端局部更改;

protected $connection = 'mysql';//可更改为database.php 自己想要的配置
curd

新增

$users = new User();
$users->username = '辉夜';
$users->password = '123';
$users->email = 'huiye@163.com';
$users->details = '123';
$users->save();

批量赋值(但需要在模型端设置批量赋值的许可;)

User::create([
'username' => '辉夜',
'password' => '123',
'email' => 'huiye@163.com',
'details' => '123',
]);

//通过提交过来的数据一次性新增
User::create(\Request::all());
//许可批量赋值,默认不可
protected $fillable = [
'username',
'password',
'email',
'details'
];
//不许可的批量赋值,不可和$fillable 同时使用
//protected $guarded = ['uid'];
//如果取消批量赋值限制,直接如下
protected $guarded = [];

更新

$users = User::find(321);
$users->username = '夜辉';
$users->save();

批量更新

User::where('username', '夜辉')
->update([
'username' => '辉夜'
]);

删除

$users = User::find(332);
$users->delete();

如果你是通过主键 id 删除,那使用 destroy(id)方法,免去查询操作;
//通过主键删除

User::destroy(328);

批量删除

$users = User::where('username', '夜辉');
$users->delete();
软删除
  1. 什么叫软删除?它相对于真实的删除,而并非真正的删除,只是隐藏了;
  2. 首先,需要在数据库创建一个字段 deleted_at(默认),用于判断是否被软删除;
  3. 默认设置这个字段为空(null),如果写入数据,成为非空状态,则说明被删除;
  4. //开启软删除功能

use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Model
{
use SoftDeletes;

}
  1. 当开启了软删除功能,之前的删除操作,都会变成更新操作,给 deleted_at 赋值;
  2. 而当我们开启了软删除的功能后,此时通过正常的数据获取列表,会自动隐藏;
//获取包含软删除的数据
$users = User::withTrashed()->get();
return [$users];

//获取所有软删除的数据
$users = User::onlyTrashed()->get();
return [$users];

//获取某个被软删除的数据(即使不是软删除的也可以搜索到)
$users = User::withTrashed()->find(82);
return [$users];

//获取某个被软删除的数据(只有软删除的数据才可以被搜索到)
$users = User::onlyTrashed()->find(82);
return [$users];

//判断是否是被软删除的数据
$users = User::withTrashed()->find(81);
return $users->trashed();

//将被软删除的数据回复正常
$users = User::onlyTrashed()->find(82);
$users->restore();

//开启软删除时的真实永久删除
$users = User::onlyTrashed()->find(82);
$users->forceDelete();
访问器
  1. 访问器:就是在获取数据列表时,拦截属性并对属性进行修改的过程;
  2. 比如;
//访问器,前固定 get,后固定 Attribute,Gender 是字段名
//参数$value 是源字段值,可修改返回
public function getGenderAttribute($value)
{
return '【'.$value.'】';
}

PS:如果字段名是两个单词中间是下划线:user_name,那么方法名:getUserNameAttribute()

  1. 我们也可以创建一个虚拟字段,用已有的数据字段进行整合,不过要进行数据追加;
//将虚拟字段追加到数据对象列表里去
protected $appends = ['info'];
//创建一个虚拟字段
public function getInfoAttribute()
{
return $this->username.'-'.$this->gender;
}

PS:注意,如果 gender 之前已经有访问器修改过,上面的方法会得到修改过的结果;
PS:如果要使用源字段进行创建虚拟字段,需要使用下面这种:

return $this->attributes['username'].'-'.$this->attributes['gender'];
修改器

修改器,相对于访问器,是在写入的时候拦截,进行修改再写入;

//修改器,写入数据时,将邮箱转换为大写
public function setEmailAttribute($value)
{
$this->attributes['email'] = strtoupper($value);
}
模型的数据集合
  1. 数据集合,就是已经将模型方法 get()获取到的数据再进行处理;
  2. 比如:map()方法,通过它可以实现类似访问器一样对字段进行处理的效果;
$users = User::get();
//使用集合方法 map 可以对输出的字段进行过滤
$women = $users->map(function ($user) {
$user->email = strtoupper($user->email);
return $user;
});
return [$women];

PS:数据集合支持连缀操作,和数据库连缀一样;
3. 使用 reject()方法,可以获取条件之外的数据内容;

$women = $users->reject(function ($user) {
return $user->gender != '女';
})->map(function ($user) {
return $user;
});
reject 移出非 true 的值
filter 筛选为 true 的值
  1. 常用的集合方法列表:
//判断集合中是否包含指定的模型实例
return $users->contains(19);
return $users->contains(User::find(19));

//返回不在集合中的所有模型
return $users->diff(User::whereIn('id', [19,20,21])->get());

//返回给定主键外的所有模型
return $users->except([19,20,21]);

//集合也有 find 方法
return $users->find(19);

//返回集合的数量
return $users->count();

//返回所有模型的主键
return $users->modelKeys();
模型的一对一关联
  • 正向关联:
    PS:主表laravel_users主键设为 id,关联主键默认就是 id,可以默认不写;
    PS:附表laravel_profiles的外键设置为 user_id,即:主表名_主键,吻合可默认不写;
创建两个 model,User.php 和 Profile.php,
//User.php,一对一关联 Profile 表
public function profile()
{
//参数 1 或:'App\Http\Models\Profile'
//参数 2:默认为 user_id,如不是需要指明
//参数 3:默认 id,如不是需要指明(注意,此参数是主表的主键,不是附表的)
return $this->hasOne(Profile::class, 'user_id', 'id');
}
 注意:Profile.php 只要建立空类即可,不需要其它,一对一调用如下:
//注意:->profile 不要加括号,以属性方式访问
$profiles = User::find(19)->profile;
return $profiles;
  • 反向关联
    定向反向关联;具体通过在 Profile 设置即可;
//profile.php
//参数 1 为主表类
//参数 2,3 和正向一致,默认对应可以不写
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
$users = Profile::find(1)->user;
return $users;

注意:方向关联时,如果附表的主键不是id,需要在profile.php设置protected $primaryKey='umeta_id';

模型的一对多关联
  • 正向关联
    本质上使用方法和一对一关联类似。
    创建一个空的 booke.php,在 User.php 进行对其关联;
//正向,一对多关联 Book 表
public function book()
{
return $this->hasMany(Book::class, 'user_id', 'id');
}
//得到蜡笔小新所有关联的书籍列表
$books = User::find(19)->book;
return $books;

获取一对多关联的数据,如果再进行筛选,可以使用下面方法:
$books = User::find(19)->book()->where('id',11)->get();
return $books;
  • 反向关联
    反向关联和一对一反向一样
模型的多对多关联
  • 正向关联
    需要一张中间表,共三张;
    (1) .users:用户表;
    (2) .roles:权限表;
    (3) .role_user:中间表:默认表名,user_id,role_id,默认外键可不指明;
创建权限表:Role.php,留空;在 User.php 设置多对多关联;
//多对多关联
public function role()
{
return $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id');
}
PS:参数 2 传中间表名,参数 34 如果是默认值,则可不传;
多对多关联输出,查看用户都拥有哪些权限;
$roles = User::find(19)->role;或者$roles = User::find(19)->role()->get();
return $roles;

获取权限列表中某一个数据,和一对多操作方法一样,但注意返回的表名称;
//注意,多对多这里 role()返回的是 role_user 表
//可以通过 dd($roles)查看,所以,where 需要用 role_id 来指明
$roles = User::find(19)->role()->where('role_id', 1)->get();
return $roles;

//当然,你也可以使用集合的方式去实现筛选
$roles = User::find(19)->role;
return $roles->where('id', 1);
  • 反向关联
//反向多对多关联,后面 id 是反的
public function user()
{
return $this->belongsToMany(User::class, 'role_user', 'role_id',
'user_id');
}
$users = Role::find(1)->user;
return $users;


  • pivot 字段
多对多会生成一个中间字段:pivot,里面包含多对多的双 id;
7. 如果想要 pivot 字段包含更多的中间表字段,可以自行添加,还可以修改字段名;
return $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id')
->withPivot('details', 'id')
->as('pivot_name');

定义多对多绑定时,可以在绑定方法内筛选数据;
$this->belongsToMany(Role::class) ... ->wherePivot('id', 1);
PS:还有 wherePivotIn
模型的关联查询
  • 使用 has()方法,可以查询某些条件下的关联查询数据;
//获取存在关联书籍的用户列表(言下之意:至少一本书)
$users = User::has('book')->get();
return $users;

//获取存在关联书籍(并超过 3 条)的用户列表
$users = User::has('book','>=', 3)->get();
return $users;

使用 whereHas()方法,创建闭包查询;
//whereHas 闭包用法
$users = User::whereHas('book', function ($query) {
//这里$query 是 book 表,通过 user_id 查询,返回 user 表数据
$query->where('user_id', 19);
})->get();
return $users;

使用 doesntHave()方法,即 has()的反向操作;
//获取不存在关联书籍的用户列表,闭包用法:whereDoesntHave()
$users = User::doesntHave('book')->get();
return $users;

使用 withCount()方法,可以进行关联统计;
//关联统计,会自动在查询结果中加上一个 book_count 字段
//统计每个用户有多少本书
$users = User::withCount('book')->get();
return $users;

//给多个关系添加统计:profile_count,book_count
$users = User::withCount(['profile', 'book'])->get();
return $users;

//关联统计再结合闭包进行筛选,还可以设置别名
$users = User::withCount(['profile', 'book as b' => function ($query) {
//这里限制被统计的记录,也就是说,当user_id=19时,才统计book记录数
$query->where('user_id', 19);
}])->get();
return $users;
模型的预加载

预加载,就是解决关联查询中产生的 N+1 次查询带来的资源消耗。
普通写法:

//获取所有书籍列表
$books = Book::all();
//遍历每一本书
foreach ($books as $book) {
//每一本书的关联用户的姓名
DebugBar::info($book->user->username);
}

PS:通过调试器 Debugbar 中 SQL 语句的分析,发现包含十多条 SQL 语句
PS:所谓 N+1 条,就是起初获取全部数据的 1 条和,遍历的 N 条;
使用 with()关键字,进行预载入设置,提前将 SQL 整合;

//with 关键字预载入
$books = Book::with('user')->get();
foreach ($books as $book) {
DebugBar::info($book->user->username);
}

PS:此时的 SQL 执行数目为:1+1 条;也支持数组多个关联 with[‘book’,‘prifile’];
PS:预加载也可以设置显示的列;

//预载入设置指定的列
$books = Book::with('user:id,username')->get();

如果每次都必须使用预载入进行关联查询,可以在模型中定义;

protected $with = ['user'];

PS:此时就可以像最初那样写代码,而不需要使用 with()方法了;
使用闭包:

$books = Book::with(['user' => function ($query) {
$query->where('id', 19);
}])->get();

PS:预载入筛选不可以使用 limit、take 方法;

有时,可能会产生逻辑判断是否查询数据,但预加载会提前关联执行;
这样,会导致资源性能的浪费,这时,可以采用延迟预载入

$books = Book::all();
if (true) {
$books = $books->load('user'); //load(['user' => function () {}])
foreach ($books as $book) {
DebugBar::info($book->user->username);
}
}

使用 loadCount()方法,可以实现延迟关联统计;

$users = User::all();
if (true) {
return $users->loadCount('book');
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值