Laravel基础
Laravel 基础
01.Laravel入门和安装
Composer安装Laravel步骤
要使用 Composer 安装 Laravel,请按照以下步骤操作:
-
确保已经安装了 Composer。如果还没有安装,请访问 https://getcomposer.org/download/ 下载并安装。
-
打开命令行或终端。
-
使用
cd
命令导航到你的项目目录,例如:cd /path/to/your/project
-
在项目目录中,运行以下命令创建一个新的Laravel项目:
composer create-project --prefer-dist laravel/laravel your_project_name
其中,
your_project_name
是你的项目名称。这将下载 Laravel 的最新版本并创建一个新的项目。 -
安装完成之后进入项目
cd your_project_name
-
将
.env.example
文件复制并重命名为.env
:cp .env.example .env
-
在
.env
文件中配置数据库连接信息。例如:DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=your_database_name DB_USERNAME=your_database_username DB_PASSWORD=your_database_password
-
生成应用密钥:
php artisan key:generate
-
运行数据库迁移和数据填充(如果有):
php artisan migrate php artisan db:seed
-
最后,启动开发服务器:
php artisan serve
这将在本地启动一个 HTTP 服务器,通常在 http://localhost:8000
上运行。现在你可以开始构建你的 Laravel 应用了。
02.路由的定义和控制器
一.路由的定义
-
什么是路由?路由就是提供接受 HTTP 请求的路径,并和程序交互的功能;
-
简单点理解,就是为了提供访问程序的 URL 地址,所做的一些设置工作;
-
phpstorm 支持 cmd 操作,左下角 Terminal 按钮展开,调整字体即可;
-
输入 php artisan serve 命令后,即支持 localhost:8000 内置服务器;
-
路由的定义文件在根目录 routes/web.php 中,可以看到welcome 页面;
-
我们创建一个路由,让它返回一段信息,并设置响应的 url 地址;
Route::get('index', function () {return "<h1>Hello World</h1>"; });
-
在路由定义上,我们采用了::get()这个方法,它接受的就是GET 提交;
-
::post()、::put()、::delete()是表单和 Ajax 的提交接受方式;
-
::any()表示不管你是哪种提交方式,我智能的全部接收响应;
-
::match()表示接收你指定的提交方式,用数组作为参数传递;
// 使用 match 必须有三个参数, any 是两个参数 Route::match(['get', 'post'], 'match', function () {return "Matched"; });
-
在路由的规则和闭包区域,我们可以设置和传递路由参数;
Route::get('index/{id}', function ($id) {return "<h1>Hello World $id</h1>"; }); // http://localhost:8000/index/5
-
上面例子中{id}表示在 url 的动态参数,比如数字 5;
-
那么闭包的$id,可以接受 url 传递过来的 5,最终输出 5;
二.创建控制器
-
MVC 模式中 C 代表控制器,用于接收 HTTP 请求,从而进行逻辑处理;
-
有两种方式可以创建控制器,IDE 直接创建,或使用命令生成一个;
php artisan make:controller TaskController
-
控制器目录在 app\Http\Controllers 下,使用 IED 会自动生成命名空间;
<?php namespace App\Http\Controllers;class TaskConterollers extends Controller {public function index(){return "task index";}public function read($id){return "id is $id";} }
-
通过设置路由来访问创建好的控制器,参数二:控制器@方法名;
use App\Http\Controllers\TaskConterollers;Route::get("/task/read/{id}", [TaskConterollers::class, 'read'])->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
03.路由参数.重定向.视图
一.路由参数
-
上一节课,我们已经学习了部分路由参数的功能,比如动态传递
{id}
; -
那么,有时这个参数需要进行约束,我们可以使用正则来限定必须是数字;
//单个参数 Route::get("/task/read/{id}", [TaskConterollers::class, 'read'])->where('id', '[0-9]+');// 多个参数 Route::get("/task/read/{id}", [TaskConterollers::class, 'read'])->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
-
如果想让约束 id 只能是 0-9 之间作用域全局范围,可以在模型绑定器里设置;
-
模型绑定器路径为:
app\Providers\RouteServiceProvider 的boot()
方法;public function boot() {$this->pattern('id', '[0-9]+'); // 全局都有效 }
-
如果 id 已经被全局约束,在某个局部你想让它脱离约束,可以如下操作:
// 全局范围的约束解除 Route::get("/task/read/{id}", [TaskConterollers::class, 'read'])->where('id', '.*');
二.路由重定向
-
可以设置访问一个路由的 URI,跳转到另一个路由的 URI,具体如下:
Route::redirect('index', 'task'); Route::redirect('index', 'task', 301); // 状态码
-
还有一个方法,可以直接让路由跳转返回 301 状态码而不用设置:
Route::permanentRedirect('index', 'task');
三.视图路由
-
在使用视图路由之前,我们先要创建一个视图(MVC)中的 V 部分;
-
使用视图路由,有三个参数:1.URI(必);2.名称(必);3.参数(选);
//参数 1:URI,localhost:8000/task //参数 2:view,resources/views/task.blade.php //参数 3:传参,{{$id}} Route::view('task', 'task', ['id'=>10]);
-
对于视图页面的创建,在 resources/views 下创建 task.blade.php;
{{--静态页面--}} task{{$id}}
-
当然,也可以使用助手函数 view()方法来实现这个功能;
//这里 view()的参数 1 是视图名称 //参数 2 传参,可选; Route::get('task', function () {return view('task', ['id'=>10]); });
-
也可以将路由直接指向控制器的方法,通过方法实现 view()引入视图;
public function index() {return view('task', ['id'=>10]); }
04.路由命名和分组
一.路由命名
-
给一个制定好的路由进行命名,可以生成 URL 地址或进行重定向;
Route::get('task', 'TaskController@index')->name('task.index');
-
在控制器区域,使用助手函数 route()来获取路由生成的 URL 地址;
//生成 url 地址,http://localhost:8000/task route('task.index'); PS:URL 是 URI 的子集,更多区别请百度;
-
route()
助手的第二参数为参数,第三参数为是否包含域名URL;// http://localhost:8000/task?id=10 route('task.index', ['id'=>10]); // /task?id=10 $url = route('task.index', ['id'=>10], false); // PS:如果需要更改成/task/10 模式,路由需要相应更改 task/{id}
-
使用 redirect()助手结合 route()生成一个重定向跳转,注意不要自我死跳;
//生成重定向 return redirect()->route('task.index', ['id'=>10]);
二.路由分组
-
路由分组功能是为了让大量路由共享路由属性,包括中间件、命名空间等;
//一个空的分组路由 Route::group([], function () {Route::get('index/{id}', function ($id) {return 'index'.$id;});Route::get('task/{id}', function ($id) {return 'task'.$id;}); });
-
可以将中间件作用域路由分组中,有两种写法,至于中间件?后续章节讲解;
//引入中间件,方法一 Route::group(['middleware'=>'中间名'], function () {}); //引入中间件,方法二 Route::middleware(['中间件'])->group(function () {});
-
可以设置路由路径前缀,通过 prefix 来设置,也有两种方法,具体如下:
//引入路由前缀,方法一 Route::group(['prefix'=>'api'],function () {}); //引入路由前缀,方法二 Route::prefix('api')->group(function () {});
-
可以设置子域名,从而限定路由可执行的域名,有两种方法,具体如下:
//引入子域名,方法一 Route::group(['domain'=>'127.0.0.1'], function () {}); //引入子域名,方法二 Route::domain('127.0.0.1')->group(function () {});
-
可以设置命名空间,让命名空间分配给控制器,让其得以访问,具体如下:
//命名空间,方法一 Route::group(['namespace'=>'Admin'],function () {}); //命名空间,方法二 Route::namespace('Admin')->group(function () {}); PS:在 Controller 目录下创建 Admin 目录,再其目录下创建的控制器命名空间如下:namespace App\Http\Controllers\Admin;
-
可以设置名称前缀,方式两种,也可以嵌套,具体如下:
//名称前缀,方式一 Route::group(['as'=>'task.'], function () {Route::get('task', 'TaskController@index')->name('index');Route::get('task/url', 'TaskController@url'); }); //名称前缀,方式二 Route::name('task.')->group( function () {}); //生成 URL $url = route('task.index'); return $url; //嵌套方式命名前缀 Route::name('task.')->group(function () {Route::name('abc.')->group(function () {Route::get('task', 'TaskController@index')->name('index');});Route::get('task/url', 'TaskController@url'); }); //生成 URL $url = route('task.abc.index'); return $url;
05.回退.当前路由.单行为
一.单行为控制器
-
之前的课程,我们简单的创建和定义了控制器,并继承了控制器基类;
-
为何要继承基类?因为继承基类后,可以使用基类的方法,比如中间件等;
-
继承基类后除了支持中间件快捷使用,还支持验证、列队等快捷方法;
public function __construct() {$this->middleware('中间件'); }
-
如果你想要定义一个只执行一个方法的控制器,可以使用单行为控制器;
-
单行为控制器使用
__invoke()
方法,可以使用命令行创建;命令:
php artisan make:controller OneController --invokable
//手工创建 class OneController extends Controller {public function __invoke(){return '单行为控制器';} }
-
单行为控制器,路由定义就不需要指定特定的方法,指定控制器即可
-
单行为控制器只是语义上的单行为,并没有限制创建更多方法访问;
Route::get('one', 'OneController');
二.路由回退
-
如果我们跳转到了一个不存在路由时,会产生 404 错误,体验不佳;
-
可以使用回退路由,让不存在的路由自动跳转到你指定的页面去;
-
注意:由于执行顺序问题,必须把回退路由放在所有路由的最底部;
Route::fallback(function () {return redirect('/'); });
-
当然,你也可以制作一个自己的 404 页面,用回退路由加载这个页面;
Route::fallback(function () {return view('404'); });
三.当前路由
-
我们可以通过使用
::current()
系列方法,来获取当前路由的访问信息;Route::get('index', function () {//当前路由信息dump(Route::current());//返回当前路由的名称return Route::currentRouteName();//返回当前路由指向的方法return Route::currentRouteAction(); })->name('localhost.index');
06.响应设置和重定向
一.响应设置
-
路由和控制器处理完业务都会返回一个发送到浏览器的响应:return;
-
比如字符串会直接输出,而数组则会输出 json 格式,本身是Response 对象;
return [1, 2, 3]; //输出 json 格式 return response([1, 2, 3]); //同上 return response()->json([1, 2, 3]); //同上
-
如果使用
response()
输出的话,可以设置状态码和响应头信息;return response('index', 201); //可以设置 HTTP 请求状态码
-
也可以给 HTTP 添加或修改标头,比如将 html 解析模式改成文本plain 模式;
return response('<b>index</b>')->header('Content-Type', 'text/plain'); //文本解析模式
-
结合上面的响应操作,再结合 view()视图功能,显示纯 HTML 代码页面;
return response()->view('task', ['id'=>10], 201)->header('Content-Type', 'text/plain');
二.路由重定向
-
重定向使用助手函数 redirect()的 to()方法,注意需要return 才能跳转
return redirect()->to('/'); //跳到首页 return redirect()->to('task'); //跳转到 task return redirect()->to('task/url'); //跳转到 task/url
-
也可以直接使用快捷方式直接进行跳转; 常用
return redirect('/'); //跳到首页
return redirect('task'); //跳转到 task
return redirect('task/url'); //跳转到 task/url
-
redirect()
助手有一个对应的 facade 模式对象;return Redirect::to('/'); //facade 模式,但需要 use 引入
-
使用
redirect()
的 route()方法,可以跳转到指定的命名路由URI;return redirect()->route('task.index'); //注意和 route()方法区别
-
使用
redirect()
的back()
方法,可以重定向到上一个页面中;常用return redirect()->back(); return back(); //快捷方式
-
使用
redirect()
的 action()方法,可以直接重定向到控制器方法;return redirect()->action('TaskController@index'); //需注册路由 return redirect()->action('TaskController@index', ['id'=>10]);
-
使用
redirect()
的 away()方法,跳转到外部链接;return redirect()->away('http://www.baidu.com'); //不带任何编码
07.资源控制器
一.资源控制器
-
声明:资源控制器是某个特定场景下的产物,完全理解需要PHP项目基础;
-
比如开发过博客系统,留言帖子系统之类,具有类似思维,否则你懂的…;
-
只是学习了PHP基础,就立刻学习框架的同学,可以过一遍即可(不影响后续)…;
-
有一种控制器专门处理CURD(增删改查),方法很多且方法名基本固定;
-
对于这种控制器,我们可以将它设置为资源型控制器,不要大量设置路由;
-
这里推荐直接使用命令行生成资源路由,比如:
BlogController
php artisan make:controller BlogController --resource
-
生成了的资源控制器会产生 7 个方法,配置好路由后会自动生成相关内容
Route::resource('blogs', BlogController::class); //单个资源路由//批量定义资源路由 // 多个路由 Route::resources(["blogs" => BlogController::class,"tasks" => TaskController::class ]);
HTTP类型 路由URI 控制器方法 路由命名 描述 GET blogs index() blogs.index 获得数据列表 GET blogs/create create() blogs.create 创建页面(表单页) POST blogs store() blogs.store 创建页的接受处理 GET blogs/{blog} show() blogs.show 获得一条数据 GET blogs/{blog}/edit edit() blogs.edit 编辑(表单页) PUT/PATCH blogs/{blog} update() blogs.update 从编辑页中接受处理 DELETE blogs/{blog} destroy() blogs.destroy 删除一条数据 -
如果我们注册了资源路由,那么如上图的资源路由 URI 和名称均自动创建生效;
http://localhost:8000/blogs/10/edit //可以访问到edit方法return route('blogs.store'); //可以通过助手route()了解是否注册
-
还有一条命令可以直接查看目前可用的路由以及命名; 常用
php artisan route:list
-
我们也可以限制资源路由只开放部分方法或排除部分方法,可以用命令查看;
// 只有 index 和 show 可以访问 Route::resource('blogs', BlogController::class)->only(['index', 'show']); // index 和 show 不可访问,剩下的都可以 Route::resource('blogs', BlogController::class)->except(['index', 'show']);
-
资源控制器还有一种不需要HTML页面方法的API路由,只提供数据接口;
//API资源,并不需要HTML页面(create,edit),会排除 Route::apiResource('blogs', 'BlogController');//批量方式 Route::apiResources(['blogs' => 'BlogController' ]);
-
当然,也支持一开始就生成一个不包含HTML页面方法的资源控制器;
-
要注意的是,对应的资源路由,直接使用api资源路由即可;创建时就说是API
php artisan make:controller CommentController --api
Route::apiResource('comments', CommentController::class);
08.资源嵌套.浅嵌套.自定义
-
声明:资源控制器是某个特定场景下的产物,完全理解需要PHP项目基础;
-
比如开发过博客系统、留言帖子系统之类,具有类似思维,否则你懂的…;
-
只是学习了PHP基础就立刻学习框架的同学,可以过一遍即可(不影响后续);
-
在一篇博文(Blog)下有多条评论(Comment),编辑某条博文下的一条评论;
-
以上需求,可以通过嵌套资源路由来实现这个功能:
php artisan make:controller CommentController --resource
//嵌套资源路由 Route::resource('blogs.comments', CommentController::class);
HTTP类型 路由URI 控制器方法 路由命名 GET blogs/{blog}/comments
index()
blogs.comments.index
GET blogs/{blog}/comments/create
create()
blogs.comments.create
POST blogs/{blog}/comments
store()
blogs.comments.store
GET blogs/{blog}/comments/{comment}
show()
blogs.comments.show
GET blogs/{blog}/comments/{comment}/edit
edit()
blogs.comments.edit
PUT/PATCH blogs/{blog}/comments/{comment}
update()
blogs.comments.update
DELETE blogs/{blog}/comments/{comment}
destroy()
blogs.comments.destroy
-
以上需求,可以通过嵌套资源路由来实现这个功能,编辑方法以及传参如下:
public function edit($blog_id, $comment_id) {return '编辑博文下的评论,博文id: ' . $blog_id . ',评论id: ' . $comment_id; }
-
而实际上,每个 id 都是独立唯一的,并不需要父 id 和子id 同时存在;
-
为了优化资源嵌套,通过路由方法
->shallow()
实现浅层嵌套方法; 取消父级// 浅层嵌套 Route::resource('blogs.comments', 'CommentController')->shallow();
-
实现后的路由及参数传递更精准:
HTTP类型 路由URI 控制器方法 路由命名 GET blogs/{blog}/comments
index()
blogs.comments.index
GET blogs/{blog}/comments/create
create()
blogs.comments.create
POST blogs/{blog}/comments
store()
blogs.comments.store
GET comments/{comment}
show()
blogs.comments.show
GET comments/{comment}/edit
edit()
blogs.comments.edit
PUT/PATCH comments/{comment}
update()
blogs.comments.update
DELETE comments/{comment}
destroy()
blogs.comments.destroy
public function edit($id) {return '评论id: ' . $id; }
-
如果觉得资源路由命名过长,可以自己自定义,有两种方式:
->name('index', 'b.c.i'); ->names(['index' => 'b.c.i']);
-
如果觉得资源路由的参数不符合你的心意,也可以改变:
->parameter('blogs', 'id'); ->parameters(['blogs' => 'blog_id', 'comments' => 'comment_id' ]);
09.表单伪造和CSRF保护
一.表单伪造
-
之前一直用的 GET 请求方式,而表单可以实现 POST 方式,我们来实验下:
-
先在 TaskController 创建两个方法,一个表单页,一个接受表单数据路由;
public function form() {return view('form'); } //表单页 Route::get('task/form', 'TaskController@form'); //接受表单数据 Route::any('task/getform', function () {return \Illuminate\Support\Facades\Request::method(); });
-
表单页以 post 发送,路由也使用 post 接受,以下表单提交会出现419 错误;
<form action="/task/getform" method="post">用户名:<input type="text" name="user"><button type="submit">提交</button> </form>
-
这是为了避免被跨站请求伪造攻击,框架提供了 CSRF 令牌保护,请求时验证;
<input type="hidden" name="_token" value="{{csrf_token()}}">
-
表单可以实现 POST 提交方式,那其它提交方式该如何实现呢?可以采用伪造技术;
<input type="hidden" name="_method" value="PUT">
-
对于 CSRF 令牌保护和表单伪造提交方式,也支持快捷方式的声明,如下:
@csrf @method('PUT')
-
如果我们想让某些 URL 关闭 csrf 验证,可以设置 csrf 白名单;
-
白名单具体设置位置在:中间件目录下的 VerifyCsrfToken.php 文件;
-
当然,不建议直接注释掉这个验证 csrf 功能的中间件;
protected $except = ['api/*', ];
10.数据库配置入门
一.配置数据库
-
框架支持原生、查询构造器和 Eloquent ORM(关系型对象映射器)来操作数据库;
-
数据库的配置在
config/database.php
,如果是本地可以直接配置.env 文件; -
我们通过.env 文件配置数据库连接的相关信息,以提供给database 读取;
DB_CONNECTION=mysql //.env DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=grade DB_USERNAME=root DB_PASSWORD=123456 'mysql' => [ //.database.php'driver' => 'mysql',... ]
-
我们可以直接创建一个新的控制器 DataController 来测试数据库部分;
-
数据库有一个专用类 DB,可以用它来实现原生查询和构造器查询;
//使用 DB 类的 select()方法执行原生 SQL $user = DB::select('select * from laravel_user'); return $user;
-
查询构造器主要通过 DB 类的各种数据库操作方法来实现,比如选定一条;
//这里省去了 laravel_,需要在 database.php 配置 $user = DB::table('user')->find(19); return [$user];
-
由于火狐浏览器自动将 JSON 显示的很美化,而 find()只返回对象;
return response()->json($user);
-
使用 Eloquent ORM 模型来操作数据库,使用命令在 Http 目录下创建模型;
php artisan make:model Http/Models/User
//使用 Eloquent ORM 构建 $user = User::all(); return $user;
上面使用模型来操作数据后,报错提示数据表是复数:users;
而我们真实的数据库表为:laravel_user,为何会这样???
前缀可以在 database.php 修改添加:laravel_,最终变为:laravel_users;
由于模型编码规范要求数据表是复数,这里的复数并不是单纯加s;
可能会加 es,可能会加 ies,也可能是 child 编程 children 之类的;
可以使用字符串助手:Str::plural()来判断英文单词的复数情况:
return Str::plural('bus'); //buses
return Str::plural('user'); //users
return Str::plural('child'); //children
你可以根据规范去更改数据表名称,或者强制使用现有的数据表名;
protected $table = 'user';
11.构造器的查询.分块.聚合
一.构造器查询
-
table()方法引入相应的表,get()方法可以查询当前表的所有数据;
//获取全部结果 $users = DB::table('users')->get();
-
first()方法,可以获取到第一条数据;
//获取第一条数据 $users = DB::table('users')->first();
-
value(字段名)方法,可以获取到第一条数据的指定字段的值;
//获取第一条数据的 email 字段值 $users = DB::table('users')->value('email');
-
find(id)方法,可以获取指定 id 的一条数据;
//通过 id 获取指定一条数据 $users = DB::table('users')->find(20);
-
pluck(字段名)可以获取所有数据单列值的集合;
//获取单列值的集合 $users = DB::table('users')->pluck('username'); $users = DB::table('users')->pluck('username', 'email');
二.分块.聚合
-
如果你一次性处理成千上万条记录,防止读取出错,可以使用chunk()方法;
//切割分块执行,每次读取 3 条,id 排序; DB::table('users')->orderBy('id')->chunk(3, function ($users) {foreach ($users as $user) {echo $user->username;}echo '------<br>'; });
-
构造器查询提供了:count()、max()、min()、avg()和 sum()聚合查询;
//聚合查询 return DB::table('users')->count(); return DB::table('users')->max('price'); return DB::table('users')->avg('price');
-
构造器查询两个判断记录是否存在的方法:exists()和 doesntexists()方法;
//判断是否存在 return DB::table('users')->where('id', 19)->exists(); return DB::table('users')->where('id', 18)->doesntExist();
PS:这里 DB::第一个使用静态,返回查询对象,然后使用->where 等各种查询方法,这些查询方法返回的还是查询对象,所以可以继续连缀操作。最后当遇到比如get()返回结果等方法时,停止连缀。所以,返回结果必须放在最后。
12.构造器的查询表达式
一.select 查询
-
select()
方法可以制定你想要的列,而不是所有列;//设置显示的列,设置列别名 $users = DB::table('users')->select('username as name', 'email')->get();
-
addSelect()
方法,可以在你基础的查询构造器上再增加想要显示的字段;//给已经构建好的查询添加更多字段 $base = DB::table('users')->select('username as name', 'email'); $users = $base->addSelect('gender')->get();
-
DB::raw()方法可以在 select()内部实现原生表达式,否则解析错误;
//结合原生 SQL 实现复杂查询 $users = DB::table('users')->select(DB::raw('COUNT(*) AS id, gender'))->groupBy('gender')->get();
-
也可以直接使用 selectRaw()方法实现内部原生;
//或者直接使用 selectRaw()方法实现原生 $users = DB::table('users')->selectRaw('COUNT(*) AS count, gender')->groupBy('gender')->get();
-
还可以通过 havingRaw()方法实现更精准的分组筛选;
//使用 havingRaw 方法实现分组筛选 $users = DB::table('users')->selectRaw('COUNT(*) AS count, gender')->groupBy('gender')->havingRaw('count>5')->get();
二.where 查询
-
where()查询,即条件查询,完整形式需要字段表达式和值三个;
//where 查询完整形式 $users = DB::table('users')->where('id', '=', 19)->get();
-
大部分情况下,是等于用的比较多,就可以省略掉=号参数;
//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();
-
如果条件较多,可以用数组来分别添加条件,具体如下:
//如果条件都是等于,查看 SQL 语句用->toSql()替换->get() $users = DB::table('users')->where(['price' => 90,'gender' => '男' ])->get(); //如果条件非等于 $users = DB::table('users')->where([['price', '>=', 90],['gender', '=', '男'] ])->get();
13.构造器的where派生查询
一.where 派生查询
-
orWhere()方法,可以通过连缀实现两个或以上的 or 条件查询;
//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();
-
whereNull()可以查询字段为 Null 的记录;
//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’)
14.构造器的排序分组.子查询
一.排序分组
-
使用
whereColumn()
方法实现两个字段相等的查询结果;//判断两个相等的字段,同样支持 orWhereColumn() //支持符号'create_time','>', 'update_time' //支持符号支持数组多个字段格式['create_time','>', 'update_time'] $users = DB::table('users')->whereColumn('create_time', 'update_time')->get();
-
使用
orderBy()
方法实现 desc 或 asc 排序功能。//支持 orderByRaw 和 orderByDesc 倒序方法 $users = DB::table('users')->orderBy('id', 'desc')->get();
-
使用
latest()
方法设置时间倒序来排,默认时间字段是 created_at;//按照创建时间倒序排,默认字段 created_at $users = DB::table('users')->latest('create_time')->toSql();
-
使用
inRandomOrder()
方法来随机排序,得到一个随机列表;//随机排序 $users = DB::table('users')->inRandomOrder()->get();
-
使用 skip()和 take()限制结果集,或使用 offset()和 limit();
//从第 3 条开始,显示 3 条 $users = DB::table('users')->skip(2)->take(3)->toSql(); $users = DB::table('users')->offset(2)->limit(3)->get();
-
使用 when()方法可以设置条件选择,执行相应的 SQL 语句;
//when 实现条件选择 $users = DB::table('users')->when(true, function ($query) {$query->where('id', 19); }, function ($query) {$query->where('username', '辉夜'); })->get();
-
如果 MySQL 在 5.7+,有支持 JSON 数据的新特性;
$users = DB::table('users')->where('list->id', 19)->first();
二.子查询
-
使用
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,一般用于子查询的手段,目的是减少开销,提升效率,深入请搜索;
-
也可以使用 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();
15.构造器的join查询
一.join 查询
-
使用 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();
-
也可以使用 leftjoin 左连接或 rightjoin 右连接实现多表查询;
$users = DB::table('users')->leftJoin('books', 'users.id', '=', 'books.user_id')->rightjoin('profiles', 'users.id', '=', 'profiles.user_id')->get();
-
使用 crossjoin 交叉连接查询,会生成笛卡尔积,再用 distinct()取消重复;
$users = DB::table('users')->crossJoin('books')->select('username', 'email')->distinct()->get();
-
如果你想要实现闭包查询,和 where 类似,只不过要用 on 和orOn 方法;
$users = DB::table('users')->join('books', function ($join) {//支持 orOn 连缀$join->on('users.id', '=', 'books.user_id');})->toSql(); // PS:on()方法后面如果想要再增加筛选条件,可以追加 where();
-
使用 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();
-
使用 union()或 unionAll()方法实现两个查询的合并操作;
//union 取消重复,unionAll 不取消重复 $query = DB::table('users'); $users = DB::table('users')->union($query)->get();
16.构造器的增删改
一.增删改操作
-
使用 insert()方法可以新增一条或多条记录;
//新增一条记录 DB::table('users')->insert(['username' => '李白','password' => '123456','email' => 'libai@163.com','details' => '123' ]); //新增多条记录 DB::table('users')->insert([[...],[...] ]);
-
使用 insertOrIgnore()方法,可以忽略重复插入数据的错误;
//忽略重复新增数据的错误 DB::table('users')->insertOrIgnore(['id' => 304,'username' => '李白','password' => '123456','email' => 'libai@163.com','details' => '123' ]);
-
使用 insertGetId()方法,获取新增后的自增 ID;
//获取新增后返回的 ID $id = DB::table('users')->insertGetId(['username' => '李白','password' => '123456','email' => 'libai@163.com','details' => '123' ]); return $id;
-
使用 update()方法,可以通过条件更新一条数据内容;
//更新修改一条数据 DB::table('users')->where('id', 304)->update(['username' => '李红','email' => 'lihong@163.com']);
-
使用 updateOrInsert()方法,可以先进行查找修改,如不存在,则新增;
//参数 1:修改的条件 //参数 2:修改的内容(新增的内容) DB::table('users')->updateOrInsert(['id'=>307],['username'=>'李黑', 'password'=>'654321', 'details'=>'123'] );
-
对于 json 数据,新增和修改的方法和正常数据类似;
//新增时,转换为 json 数据 'list' => json_encode(['id'=>19]) //修改时,使用 list->id 指定 DB::table('users')->where('id', 306)->update(['list->id' => 20]);
-
更新数据时,可以使用自增 increment()和自减 decrement()方法;
//默认自增/自减为 1,可设置 DB::table('users')->where('id', 306)->increment('price'); DB::table('users')->where('id', 306)->increment('price', 2);
-
使用 delete()删除数据,一般来说要加上 where 条件,否则清空;
//删除一条数据 DB::table('users')->delete(307); DB::table('users')->where('id', 307)->delete(); //清空 DB::table('users')->delete(); DB::table('users')->truncate();
17.模型的定义
一.默认设置
-
框架可以使用 Eloquent ORM 进行数据库交互,也就是关系对象模型;
-
在数据库入门阶段,我们已经创建了一个 User.php 模型,如下:
php artisan make:model Http/Models/User
默认在 app 目录 -
而调用的时候,我们也知道表名要遵循它默认规则,修改为复数,或特定;
class User extends Model {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;
-
如果你想自定义时间戳的格式,可以设置;
protected $dateFormat = 'U';
-
可以更改创建时间 created_at 和更新时间 updated_at 字段名;
const CREATED_AT = 'create_time'; const UPDATED_AT = 'update_time';
-
默认读取
database.php
配置的数据库连接,也可以在模型端局部更改;protected $connection = 'mysql';
二.模型定义
-
之前在查询构造器部分,把常用的数据库操作基本讲完,模型大体相同;
-
比如,我们要查询所有数据,直接使用模型::all()即可;
//查询所有记录 $users = User::get(); //或 all() return [$users];
-
也可以像查询构造器一样,添加各种各样的条件,写法一样;
//查询性别为男,价格大于 90,限制显示 2 条 $users = User::where([['gender', '=', '男'],['price', '>', 95] ])->limit(2)->get();
-
虽然安装了插件,但模型还是没有代码提示,可以通过安装插件解决;
composer require barryvdh/laravel-ide-helperphp artisan ide-helper:generate – 为 Facades 生成注释 php artisan ide-helper:models – 为数据模型生成注释 php artisan ide-helper:meta – 生成 PhpStorm Meta file
-
其它查询方法基本和查询构造器一样,如果有不一样,参考错误提示;
-
这里列出官网给出示例的方法,对照实验(结合详细文档,重复较多);
(1) .find(1) //通过主键查找 (2) .first() //查找第一个 (3) .firstWhere() //找到查询中的首个 (4) .find([1,2,3]) //通过数组查找 (5) .firstOr() //查找首个返回,支持闭包 (6) .firstOrFail() //找不到时返回异常 (7) .count()、max()等集合 //集合操作
PS:还有很多在查询构造器中的方法,比如排序、分组子查询等等都可以使用(并未一一验证)。
18.模型的增删改
一.增删改操作
-
新增方法如下,注意:默认模型接管 created_at 和 updated_at;
$users = new User(); $users->username = '辉夜'; $users->password = '123'; $users->email = 'huiye@163.com'; $users->details = '123'; $users->save();
-
更新,只要是查找到一条数据的情况下使用 save()就是更新;
$users = User::find(321); $users->username = '夜辉'; $users->save();
-
使用 update()方法实现批量更新;
User::where('username', '夜辉')->update(['username' => '辉夜']);
-
使用 create()方法实现新增,但需要在模型端设置批量赋值的许可;
User::create(['username' => '辉夜','password' => '123','email' => 'huiye@163.com','details' => '123', ]); //许可批量赋值,默认不可 protected $fillable = ['username','password','email','details' ]; //不许可的批量赋值,不可和$fillable 同时使用 //protected $guarded = ['uid']; //如果取消批量赋值限制,直接如下 protected $guarded = [];
PS:必须在模型中定义批量赋值的可填充字段,否则无法生效;防止用户不小心设置新值;
-
使用 delete()方法,可以删除数据;
$users = User::find(332); $users->delete(); //批量删除 $users = User::where('username', '夜辉'); $users->delete();
-
如果你是通过主键 id 删除,那使用 destroy(id)方法,免去查询操作;
//通过主键删除 User::destroy(328);
19.批量赋值和软删除
一.批量赋值
- 上一节增删改中,新增中我们发现需要进行批量赋值的许可;
- 一般情况下,是为了防止提交过来的字段在部分场景中不需要或不能;
- 所以,我们需要通过黑白名单机制进行过滤掉必要的字段;
//通过提交过来的数据一次性新增
User::create(\Request::all());
二.软删除
-
什么叫软删除?它相对于真实的删除,而并非真正的删除,只是隐藏了;
-
首先,需要在数据库创建一个字段 deleted_at(默认),用于判断是否被软删除;
-
默认设置这个字段为空(null),如果写入数据,成为非空状态,则说明被删除;
-
开启软删除的功能,需要在模型端设置一下:
use SoftDeletes; //开启软删除功能
-
当开启了软删除功能,之前的删除操作,都会变成更新操作,给deleted_at 赋值;
//删除一 $users = User::find(82); $users->delete(); //删除二 User::destroy(81);
-
而当我们开启了软删除的功能后,此时通过正常的数据获取列表,会自动隐藏;
//软删除的数据不可见 $users = User::get(); return [$users]; //单独获取被软删除的数据不行 $users = User::find(82); return [$users];
-
如果需要查询包含软删除的数据,通过
withTrashed()
方法实现;//获取包含软删除的数据 $users = User::withTrashed()->get(); return [$users]; //获取某个被软删除的数据(即使不是软删除的也可以搜索到) $users = User::withTrashed()->find(82); return [$users];
-
如果只想搜索出被软删除的数据,通过 onlyTrashed()方法实现;
//获取所有软删除的数据 $users = User::onlyTrashed()->get(); return [$users]; //获取某个被软删除的数据(只有软删除的数据才可以被搜索到) $users = User::onlyTrashed()->find(82); return [$users];
-
如果要对这个数据进行软删除的判断,是否是被软删除的,可以使用trashed();
//判断是否是被软删除的数据 $users = User::withTrashed()->find(81); return $users->trashed();
-
如果想将软删除的数据恢复正常(类似从回收站还原),使用restore()方法;
//将被软删除的数据回复正常 $users = User::onlyTrashed()->find(82); $users->restore();
-
如果开启了软删除,还需要强行真实的永久删除,可以使用forceDelete()方法;
//开启软删除时的真实永久删除 $users = User::onlyTrashed()->find(82); $users->forceDelete();
20.模型的作用域
一.本地作用域
-
很多情况下,我们在数据查找时有一部分条件会被重复且大量使用;
-
而这个条件,可能只是在这个模型对应的数据表使用,别的表并不使用;
-
那么这种情况,可以使用本地作用域的方式,将常用的 SQL 封装起来;
-
比如:用户模块中,我们大量查询需要查询性别为男,且其它条件的SQL;
$users = User::where('gender', '男')->where('price', '>', 90)->get();
PS:我们可以将性别为男这个片段,封装成一个单独的方法,然后统一在这个模型下调用;
//App\Http\Models; //本地作用域,搜索自动添加为“男”的条件 //语法:scope 开头,后面名称尽可能包含语义 public function scopeGenderMale($query) {return $query->where('gender', '男'); } //当然,如果感觉单词太长,直接 gm()也行 $users = User::genderMale()->where('price', '>', 90)->get();
-
上面的方法比较死板,适合简单粗暴,如果想要灵活多变,支持传递参数;
//参数可以是 1 个或多个 $users = User::gender('女', -3)->where('price', '>', 90)->get(); //参数 2 和 3,接受控制器传递过来的 1,2 public function scopeGender($query, $value, $value2) {return $query->where('gender', $value)->where('status', $value2); }
二.全局作用域
-
全局作用域,顾名思义就是在任意地方都可以有效的封装条件;
-
比如有个需求,不管在哪里操作,总是显示 status 为 1 的用户;
-
首先在 app 目录下创建一个用于全局作用域的目录:Scopes;
-
创建一个用于设置 status 为 1 的全局作用域的类,它需要实现scope 接口;
namespace App\Scopes; //这里引用代码自动生成 use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; class StatusScope implements Scope {/*** @inheritDoc*/public function apply(Builder $builder, Model $model){// TODO: Implement apply() method.return $builder->where('status', 1);} }
-
此时,还不能实现全局,因为需要在模型设置个开关,让其富有灵活性;
//启用全局作用域 protected static function booted() {parent::booted(); // TODO: Change the autogenerated stubstatic::addGlobalScope(new StatusScope()); }
PS:而在控制器端,并不需要做任何设置,即可自动添加 status=1 的条件;
-
当然,如果这个全局只是针对某个模块,并不需要创建一个全局类,直接闭包即可;
static::addGlobalScope('status', function (Builder $builder) {return $builder->where('status', 1); });
PS:注意 Builder 引入的文件和全局类引入的文件一致,如果引入别的同名类会错;
-
如果某个查询,并不需要这个全局条件,可以单独移出掉;
//取消名称为 status 的全局 $users = User::withoutGlobalScope('status')->get(); //取消全局类的条件 $users = User::withoutGlobalScope(StatusScope::class)->get();
PS:还有 withoutGlobalScopes([])方法,传递参数取消多个全局;
21.模型的访问器和修改器
一.访问器
-
访问器:就是在获取数据列表时,拦截属性并对属性进行修改的过程;
-
比如,我们在输出性别时,在性别左右加上括号,或给邮件转换为大写;
//访问器,前固定 get,后固定 Attribute,Gender 是字段名 //参数$value 是源字段值,可修改返回 public function getGenderAttribute($value) {return '【'.$value.'】'; }
PS:如果字段名是两个单词中间是下划线:
user_name
,那么方法名:getUserNameAttribute()
-
我们也可以创建一个虚拟字段,用已有的数据字段进行整合,不过要进行数据追加;
//将虚拟字段追加到数据对象列表里去 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); }
-
可以添加默认的日期列,默认 created_at 和 updated_at;
//设置可以自动写入日期的列 protected $dates = ['details' ];
-
可以设置字段输出的类型,比如设置一个布尔型,输出时就是true 和false;
//设置字段类型 protected $casts = ['details' => 'boolean' ];
22.集合的使用
一.创建集合
-
什么是集合?即:它是一种更具读取性和处理能力的数组封装;
-
比如,我们从数据库得到的数据列表,它就是一种集合;
-
数据集合,提供了大量的方法方便我们进行各种操作;
-
除了数据库对象返回的数据集合之外,我们还可以自行创建数据集合;
//创建一个数据集合 $collection = collect(['张三', '李四', '王五', null]); //使用 dd 查看它的类型 dd($collection); //直接 return 可以返回 return $collection;
-
数据集合提供了大概有三十多个(31?)处理数据集合的方法,可链式调用;
-
这里我们把最常用的演示一遍,剩下的所有,可以自行参考手册方法列表;
//以底层数组形式输出 return $collection->all(); //map 方法,类似访问器,可修改输出 return $collection->map(function ($value, $key) {return $key.'['.$value.']'; }); //支持链式,reject 移出非 true 的值 return $collection->reject(function ($value, $key) {return $value === null; })->map(function ($value, $key) {return $key.'['.$value.']'; }); //filter 筛选为 true 的值,和 reject 相反 return $collection->filter(function ($value, $key) {return $value === null; });//search 找到后返回 key,找不到返回 false return $collection->search('王五'); //集合的分割 return $collection->chunk(2); //迭代输出 $collection->each(function ($item, $key) {echo $item; });
PS:这里就介绍这么多,更多的我们去手册扫一遍。做项目时,凭着记忆回头查,慢慢就熟了;PS:下一节,我们会花一节课,把最常用的方法再运行一遍加深印象;
-
如果三十多个方法都没有你要的,还可以自定义方法,比如说所有英文大写;
$collection = collect(['Mr.Zhang', '李四', '王五', null]); Collection::macro('toUpper', function () {//dd($this);return $this->map(function ($value) {return strtoupper($value);}); }); return $collection->toUpper();
23.集合的常用方法
一.常用方法
-
all()方法,转换为属性形式输出,使用 dd 方法看类型;
$collection = collect([1, 2, 2, 3, 4, 4, 4]); dd($collection->all()); // PS:$collection->dd()方法可以以 dd()模式输出,还有 dump()模式;
-
avg()方法返回平均值;
//返回平均值 $collection = collect([1, 2, 3, 4]); return $collection->avg(); //返回分组平均值 $collection = collect([['男'=>1], ['女'=>1], ['男'=>3]]); return $collection->avg('男');
-
count()方法返回集合总数;
return $collection->count(); // PS:相关的还有 sum()、min()、max()等统计;
-
countBy()方法返回数值出现的次数或回调函数指定值出现的次数;
$collection = collect([1, 2, 2, 3, 4, 4, 4]); return $collection->countBy(); //回调搜索相同指定片段的值的次数 $collection = collect(['xiaoxin@163.com', 'yihu@163.com', 'xiaoying@qq.com']);return $collection->countBy(function ($value) {return substr(strrchr($value, '@'), 1); }); // PS:相关的还有 groupBy()、keyBy()方法;
-
diff()方法返回集合数组之间不相同的部分,组合新的集合;
//diff 返回两个集合中不相同的 $collection = collect([1, 2, 3, 4, 5]); return $collection->diff([3, 5]); // PS:其中还有 diffAssoc()、diffKeys()派生方法;
-
duplicates()返回重复的值;
$collection = collect([1, 2, 2, 3, 4, 5, 5, 6]); return $collection->duplicates(); //严格派生方法:duplicatesStrict()
-
first()返回成立后的第一个值;
//返回判断成立的第一条数值 $collection = collect([1, 2, 3, 4]); return $collection->first(function ($value) { return $value > 2; }); // PS:相关的还有 every()、except()、only()、firstWhere()、last()等方法;
-
flatten()将多维数组转换为一维;
$collection = collect(['name'=>'Mr.Lee', 'details'=>['gender'=>'男', 'age'=>100]]); return $collection->flatten();
-
get()通过键名找值;
$collection = collect(['name'=>'Mr.Lee', 'gender'=>'男']); return $collection->get('name'); // PS:相关的还有 pluck()等;
-
has()判断集合中是否存在指定键;
return $collection->has('name');
-
pop()移出集合中最后一个值;
$collection = collect([1, 2, 3, 4, 5]); //$collection->pop(); return $collection; // PS:相关的还有 pull()、push()、put()方法
-
slice()返回指定值后续的集合;
$collection = collect([1, 2, 3, 4, 5]); return $collection->slice(3);
PS:相关的还有 splice()等方法;
-
sort()返回指定值后续的集合;
$collection = collect([3, 1 , 5, 2, 7]); return $collection->sort()->values(); //需要配合 values()方法
PS:相关的有 sortBy()、sortByDesc()、sortKeys()等;
-
where()系列方法,和数据库条件一样;
$collection = collect([['name'=>'Mr.Lee', 'gender'=>'男'],['name'=>'Miss.Zhang', 'gender'=>'女'] ]); return $collection->where('name', 'Mr.Lee');
24.模型的数据集合
一.数据集合
-
数据集合,就是已经将模型方法 get()获取到的数据再进行处理;
-
比如:map()方法,通过它可以实现类似访问器一样对字段进行处理的效果;
$users = User::get(); //使用集合方法 map 可以对输出的字段进行过滤 $women = $users->map(function ($user) {$user->email = strtoupper($user->email);return $user; }); return [$women]
PS:数据集合支持连缀操作,和数据库连缀一样;
-
使用 reject()方法,可以获取条件之外的数据内容;
$women = $users->reject(function ($user) {return $user->gender != '女'; })->map(function ($user) {return $user; });
-
下面列出常用的集合方法列表:
//判断集合中是否包含指定的模型实例 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(); //返回主键的所有模型 return $users->only([19,20,21]); //返回集合中的唯一模型 return $users->unique();
25.模型的一对一关联
一.关联概念
- 关联模型,即:两张或以上的表进行一定规则的绑定关联;
- 比如:一个学生(学生表)对应一张个人信息卡(信息表),这种就是一对一;
- 再比如:一篇博文(帖子表)对应多个评论(评论表),这种就是一对多;
- 再再比如:一个用户(用户表)对应多个职位(权限表), 而一个职位又可以有多个用户;那么,这种就是多对多关联;
- 自然,还有更多更复杂的关联,都是基于此的,我们只探讨这三种;
- 既然是关联,当然会有绑定的概念,当有数据库操作,关联表也会跟着变动;
- 这就是关联模型的意义;
二.一对一关联
-
一对一关联,我们选择两张表来做演示,首先看下两张表的结果对比;
-
由于之前 Models 下的 User.php 模型代码很多了,改成.bak 后重建;
-
创建两个 model,User.php 和 Profile.php,并使用命令实现提示;
php artisan ide-helper:models
//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;