Laravel: Up & Running 中文版
  • Laravel Up and Running A Framework for Building Modern PHP Apps
  • 为什么是Laravel
    • 为什么使用框架
    • “自己写”
    • 一致性与灵活性
    • 简短PHP Web框架历史
      • Ruby on Rails
      • PHP框架的涌入
      • CodeIgniter的优劣
      • Laravel 1, 2,和 3
      • Laravel 4
      • Laravel 5
    • Laravel 特别之处
      • Laravel哲学
      • Laravel如何让开发者感到幸福
      • Laravel 社区
    • 是如何运作的
    • 为什么是Laravel
  • 创建Laravel开发环境
    • 系统要求
    • Composer
    • 本地开发环境
      • Laravel Valet
      • Laravel Homestead
    • 创建一个新的Laravel项目
      • 使用Laravel安装工具安装Laravel
      • 使用Composer的create-project功能安装Laravel
      • Lambo:一款增强的"Laravel New"工具
    • Laravel的目录结构
      • 文件夹
      • 其他零散文件
    • 配置
      • .env文件
    • 运行
    • 测试
    • 总结
  • 路由与控制器
    • MVC HTTP和REST简介
      • 什么是MVC
      • HTTP verbs
      • 什么是REST
    • 定义路由
      • Route Verbs
      • 处理路由
      • 路由参数
      • 路由命名
    • 路由组
      • 中间件
        • 在控制器内应用中间件
        • 频率限制
      • 路径前缀
      • 兜底路由
      • 子域路由
      • 命名空间前缀
      • 名称前缀
    • 路由签名
      • 添加签名
      • 修改路由可以访问签名链接
    • 视图
      • 直接使用Route::view()返回简单路由
      • 使用View Composer在视图间共享变量
    • 控制器
      • 获取用户输入
      • 将依赖注入到控制器
      • 资源控制器
      • API 资源控制器
      • 单动作控制器
    • 路由模型绑定
      • 隐式路由模型绑定
      • 自定义路由模型绑定
    • 路由缓存
    • 表单请求方法伪造
      • Laravel内的HTTP verb
      • HTML 表单中的HTTP方法伪造
    • CSRF保护
    • 重定向
      • redirect()->to()
      • redirect()->route()
      • redirect()->back()
      • 其他重定向方法
      • redirect()->with()
    • 关于请求
    • 自定义响应
      • response()->make()
      • response()->json() 和 ->jsonp()
      • response()->download(), ->streamDownload(), 和 ->file()
    • 测试
    • 总结
  • Blade 模板引擎
    • 输出数据
    • 控制结构
      • 条件
      • 循环
    • 模板继承
      • 包含视图
      • 使用堆栈
      • 使用组件与插槽
    • 视图Composer和服务注入
      • 使用视图composers绑定数据到视图
      • Blade 服务注入
    • 自定义Blade指令
      • 自定义指令传参
      • 示例:多租户的自定义Blade指令
      • 更简单的if语句自定义指令
    • 测试
    • 总结
  • 数据库和Eloquent
    • 配置
      • 数据库连接
      • 其他数据库配置选项
      • 定义迁移
        • 创建一个迁移
        • 创建表格
        • 创建字段
        • 构建额外属性
        • 丢弃表格
        • 修改字段
        • 索引和外键
      • 运行迁移
    • 填充
      • 创建一个填充
      • 模型工厂
    • 查询器
      • DB facade的基础用法
      • 原生SQL
      • 使用查询器
      • 事务
    • Eloquent介绍
      • 创建和定义Eloquent模型
      • 使用Eloquent检索数据
      • 使用Eloquent插入和更新
      • 使用Eloquent删除
      • 作用域
      • 使用访问,赋值和属性转换自定义字段
      • Eloquent集合
      • Eloquent序列化
      • Eloquent关系
      • 子记录更新父记录时间戳
    • Eloquent事件
    • 测试
    • 总结
  • 前端组件
    • Laravel 混合
      • Mix 文件夹结构
      • 运行Mix
      • Mix提供了什么
    • 前端预设和授权脚手架
      • 前端预设
    • 分页
    • 信息包
      • 命名错误包
    • 字符串助手,多元化和本地化
      • 字符串助手和多元化
      • 本地化
    • 测试
      • 测试Message和错误包
      • 翻译和本地化
    • 总结
  • 收集和处理用户数据
    • 注入一个请求对象
      • $request->all()
      • $request->except()和$request->only()
      • $request->has()
      • $request->input()
      • $request->method() 和->isMethod()
      • 数组输入
      • JSON 输入($request->json())
    • 路由数据
      • 来自请求
      • 来自路由参数
    • 上传文件
    • 验证
      • Request对象上的validate()
      • 手动验证
      • 自定义验证规则
      • 显示验证错误信息
    • 表单请求
      • 创建一个表单请求
      • 使用表单请求
    • Eloquent 模型批量赋值
    • {{ 与 {!!
    • 测试
    • 总结
  • Artisan 和 Tinker
    • Artisan 介绍
    • 基础Artisan命令
      • 选项
      • 分组的命令
    • 编写自定义Artisan命令
      • 一个简单的命令
      • 参数和选项
      • 使用输入
      • 提示
      • 输出
      • 基于闭包的命令
    • 在普通代码调用Artisan命令
    • Tinker
    • Laravel Dump 服务
    • 测试
    • 总结
  • 用户认证与授权
    • 用户模型与迁移
    • 使用auth()全局辅助和Auth Facade
    • 认证控制器
      • RegisterController
      • LoginController
      • ResetPasswordController
      • ForgotPasswordController
      • VerificationController
    • Auth::routes()
    • 认证脚手架
    • ”记住我“
    • 手动认证用户
    • 手动登出用户
    • 认证中间件
    • 邮箱验证
    • Blade认证指令
    • 守卫
      • 更改默认守卫
      • 不更改默认使用其他守卫
      • 添加新守卫
      • 闭包请求守卫
      • 创建一个自定义用户提供者
      • 非关系数据库的自定义用户提供者
    • 认证事件
    • 授权(ACL)和角色
      • 定义授权角色
      • Gate Facade(注入Gate)
      • 资源Gates
      • 授权中间件
      • 控制器授权
      • 检查用户实例
      • Blade检查
      • 拦截检查
      • 策略
    • 测试
    • 总结
  • 请求,响应,和中间件
    • Laravel的请求生命周期
      • 启动应用程序
      • 服务提供者
    • 请求对象
      • 在Laravel获取一个请求对象
      • 获取请求的基本信息
    • 响应对象
      • 在控制器内使用和创建响应对象
      • 序列化响应类型
    • Laravel和中间件
      • 中间件介绍
      • 创建自定义中间件
      • 绑定中间件
      • 给中间件传参
    • 可信代理
    • 测试
    • 总结
  • 容器
    • 依赖注入简介
    • 依赖注入与Laravel
    • app()全局辅助函数
    • 如何连接容器
    • 绑定类到容器
      • 绑定到闭包
      • 绑定到单例,Aliases和实例
      • 绑定具体实例到接口
      • 上下文绑定
    • Laravel框架内的构造注入
    • 方法注入
    • Facades和容器
      • Facade是如何工作的
      • 实时Facades
    • 服务提供者
    • 测试
    • 总结
  • 测试
  • 编写APIs
    • REST基础-JSON APIs
    • 控制器组织和JSON返回
    • 读取和发送Headers
      • 在Laravel中发送响应头
      • 在Laravel中读取请求头
    • Eloquent 分页
    • 排序和过滤
      • 排序你的API 结果
      • 过滤你的API结果
    • 转换结果
    • API 资源
      • 创建一个资源类
      • 资源集合
      • 嵌套关系
      • 对API资源使用分页
      • 有条件地应用属性
      • API资源的更多自定义
    • API 认证和Laravel Passport
      • OAuth 2.0 简介
      • 安装Passport
      • Passport的API
      • Passport的有效授权类型
      • 使用Passport API和vue组件管理客户端和令牌
      • Passport 作用域
      • 部署Passport
    • API Token认证
    • 自定义404响应
      • 触发回退路由
    • 测试
    • 总结
  • 存储和检索
Powered by GitBook
On this page

Was this helpful?

  1. 数据库和Eloquent
  2. 查询器

使用查询器

到目前为止,我们还没有真正的使用查询器,之前我们在DB facade上面调用了一些简单方法,让我们构建一些查询.

查询器将方法链接到一起从而构建查询,在链的末尾你可以使用一些方法(可能是get())来触发查询.

来让我们看一个简单的例子

$usersOfType = DB::table('users')
        ->where('type', $type)
        ->get();

这里,我们创建了查询,查询users表格,查询条件是type,然后我们执行查询获取结果

让我们看下可用的链式方法有哪些,这些方法我称之为约束方法,修改方法,条件方法和结束/返回方法

约束方法

这些方法进行约束查询,并返回较小的数据子集

select()

选择查询的列

$emails = DB::table('contacts')
    ->select('email', 'email2 as second_email')
    ->get();
// Or
$emails = DB::table('contacts')
    ->select('email')
    ->addSelect('email2 as second_email')
    ->get();

where()

你可以使用WHERE限制返回内容的范围,默认情况下,where()接收3个参数,列,比较运算符,值

$newContacts = DB::table('contact')
            ->where('created_at', '>', now()->subDay())
            ->get();

然而,如果第二个运算符是=,那么可以省略这个参数

$vipContacts = DB::table('contacts')->where('vip',true)->get();

如果要组合where()语句,你可以再另外一个后面追加或者传递数组

$newVips = DB::table('contacts')
            ->where('vip', true)
            ->where('created_at', '>', now()->subDay());
// Or
$newVips = DB::table('contacts')->where([['vip', true],
            ['created_at', '>', now()->subDay()],
        ]);

orWhere()

创建一个简单的OR WHERE

$priorityContacts = DB::table('contacts')
            ->where('vip', true)
            ->orWhere('created_at', '>', now()->subDay())
            ->get();

若要创建具有多个条件的更复杂OR WHERE语句,请给orWhere传递闭包

$contacts = DB::table('contacts') 
    ->where('vip', true)
    ->orWhere(function ($query) {
        $query->where('created_at', '>', now()->subDay())
         ->where('trial', false);
    }) 
    ->get();

多个where()和orWhere()混合调用

如果将orWhere()调用与多个where()调用结合使用,则需要非常小心,以确保查询按您认为的方式进行。这并不是因为Laravel有任何错误,而是因为像下面这样的查询可能无法实现您期望的结果:

$canEdit = DB::table('users')
            ->where('admin', true)
            ->orWhere('plan', 'premium')
            ->where('is_plan_owner', true)
            ->get();

SELECT * FROM users 
    WHERE admin = 1
    OR plan = 'premium' 
    AND is_plan_owner = 1;

如果要编写SQL,上面的示例中明确指出“if this or(this and this)”,则需要将闭包传递到orWhere()中调用:

$canEdit = DB::table('users')
            ->where('admin', true)
            ->orWhere(function ($query) {
                $query->where('plan', 'premium')
                    ->where('is_plan_owner', true);
            })
            ->get();
SELECT * FROM users 
    WHERE admin = 1
    OR (plan = 'premium' AND is_plan_owner = 1);

whereBetween(colName, [low, high])

允许查询返回介于两个值之间的行(包含两个值)

$mediumDrinks = DB::table('drinks')
            ->whereBetween('size', [6, 12])
            ->get();

同样适用于whereNotBetween(),但是结果会反转

whereIn(colName, [1, 2, 3])

返回列表范围的行

$closeBy = DB::table('contacts')
        ->whereIn('state', ['FL', 'GA', 'AL'])
        ->get();

同样适用于whereNotIn(),结果会反转

whereNull(colName) 和 whereNotNull(colName)

查询NULL或者Not NULL

whereRaw()

可以给where传递原生非转义字符串

$goofs = DB::table('contacts')->whereRaw('id = 12345')->get()

小心SQL注入!

传递给whereraw()的任何SQL查询都不会被转义。小心使用此方法;这是应用程序中SQL注入攻击的主要机会。

whereExists()

允许你传递子查询,并至少返回一条记录,假设你想获取至少有一条留言的用户

$commenters = DB::table('users')
            ->whereExists(function ($query) {
                $query->select('id')
                ->from('comments')
                ->whereRaw('comments.user_id = users.id');
            })
            ->get();

distinct()

返回与其他记录比较后的记录,通常与select()搭配使用,因为如果你使用了主键,则不会有重复的记录

$lastNames = DB::table('contacts')->select('city')->distinct()->get();

修改方法

这些方法更改了查询结果,不仅仅是限制了结果

orderBy(colName, direction)

查询结果排序,第二个参数可以是asc(默认值,升序)或desc(降序)

 $contacts = DB::table('contacts')
            ->orderBy('last_name', 'asc')
            ->get();

groupBy() 和 having() 或者 havingRaw()

将结果按列分组。或者,having()和havingraw()允许您根据组的属性筛选结果。例如,您可以只查找人口至少为30人的城市

$populousCities = DB::table('contacts')
            ->groupBy('city')
            ->havingRaw('count(contact_id) > 30')
            ->get();

skip()和take()

最常用于分页,它们允许您定义返回多少行,以及在开始返回之前跳过多少行,就像分页系统中的页码和页面大小一样。

// returns rows 31-40
$page4 = DB::table('contacts')->skip(30)->take(10)->get();

latest(colName)和oldest(colName)

通过传递的列进行升序(oldest)或者降序(latest)排列,如果没传值则按照created_at排列

inRandomOrder()

随机排序结果

条件方法

Laravel 5.2以及更高版本有两个方法,可以通过传递值的布尔状态对内容进行条件判断(需要传递个闭包)

when()

第一个参数传"真"则会执行闭包内的查询,第一个参数传"假"那么什么都不做,注意第一个参数应该是布尔(true,false),一个可选值($status,从用户输入中提取,并默认为null)或返回一个值的闭包,重要的是要返回true或者false,例如

$status = request('status'); // Defaults to null if not set
$posts = DB::table('posts')
    ->when($status, function ($query) use ($status) {
        return $query->where('status', $status); })
    ->get();

$posts = DB::table('posts')
    ->when($ignoreDrafts, function ($query) { 
        return $query->where('draft', false);
    }) ->get();

您还可以传递第三个参数,即另一个闭包,只有在第一个参数false时才会应用该闭包。

unless()

与when相反,如果第一个参数为false,则会运行第二个闭包

结束/返回方法

终止查询链并触发SQL查询,如果在查询链没有调用这些方法,那么你将得到一个查询器实例,如果在查询链上执行了这些方法,那么你将得到具体的记录.

get()

获取查询器的所有结果

$contacts = DB::table('contacts')->get();
$vipContacts = DB::table('contacts')->where('vip', true)->get();

first()和firstOrFail()

获取第一条结果,就像Like,但是它只返回一条

$newestContact = DB::table('contacts')
            ->orderBy('created_at', 'desc')
            ->first();

如果没有结果,first()将自动失败,而firstorfail()将引发异常。

如果将列名数组传递给任一方法,它将只返回这些列的数据,而不是所有列的数据。

find(id)和findOrFail(id)

与first()类似,传递一个与主键对应的ID进行查找,如果ID对应的不存在,find会失败,而findOrFail会异常

$contactFive = DB::table('contacts')->find(5);

value()

从第一行提取单个字段,像first()但是你只想获取单个列

$newestContactEmail = DB::table('contacts')
            ->orderBy('created_at', 'desc')
            ->value('email');

count()

返回所有匹配结果的计数

$countVips = DB::table('contacts')
    ->where('vip', true)
    ->count();

min()和max()

返回特定列的最小或最大值

$highestCost = DB::table('orders')->max('amount');

sum()和avg()

返回特定列中所有值的总和或平均值

$averageCost = DB::table('orders')
            ->where('status', 'completed')
            ->avg('amount');

使用DB::raw在查询器中写原生查询

之前看到过一些方法用于原生语法-例如select有一个对应的selectRaw方法可以给其传递字符串用于查询,然后放到WHERE语法后

当然你也可以调用DB::raw()来实现相同的结果

$contacts = DB::table('contacts')
        ->select(DB::raw('*, (score * 100) AS integer_score'))
        ->get();

连接

定义联合查询有时有点困难,但是Laravel的查询器做的比较好,如例子

$users = DB::table('users')
        ->join('contacts', 'users.id', '=', 'contacts.user_id')
        ->select('users.*', 'contacts.name', 'contacts.status')
        ->get();

join()创建了一个连接查询,你可以用链式写法组合多个join,或者使用leftJoin来创建左连接

最后,你也可以给join传递闭包创建更复杂的连接查询

DB::table('users')
            ->join('contacts', function ($join) {
                $join
                    ->on('users.id', '=', 'contacts.user_id')
                    ->orOn('users.id', '=', 'contacts.proxy_user_id');
            })->get();

组合

通过首先创建两个查询,然后使用union()或unionall()方法,可以将它们联合起来(将它们的结果组合成一个结果)

$first = DB::table('contacts')
        ->whereNull('first_name');
        
$contacts = DB::table('contacts')
    ->whereNull('last_name')
    ->union($first)
    ->get();

插入

插入非常简单,传递一个数组插入单条记录,传递数组的数组,插入多条记录,使用insertGetId()替代insert()可以自动生成主键

$id = DB::table('contacts')->insertGetId([
        'name' => 'Abe Thomas',
        'email' => 'athomas1987@gmail.com',
]);
DB::table('contacts')->insert([
        ['name' => 'Tamika Johnson', 'email' => 'tamikaj@gmail.com'],
        ['name' => 'Jim Patterson', 'email' => 'james.patterson@hotmail.com'],
]);

更新

更新也非常简单,创建更新查询只需要将数组传递给它

DB::table('contacts')
        ->where('points', '>', 100)
        ->update(['status' => 'vip']);

还可以使用increment()和decrement()方法快速增加和减少列。第一个参数是列名,第二个(可选)是要递增/递减的数字

DB::table('contacts')->increment('tokens', 5);
DB::table('contacts')->decrement('tokens');

删除

删除更简单,在查询结尾调用delete()即可

DB::table('users')
        ->where('last_login', '<', now()->subYear())
        ->delete();

您还可以截断表,该表将删除每一行并重置自增ID。

JSON操作

如果你有一个JSON列,你可以使用箭头语法来更新或选择JSON结构

// Select all records where the "isAdmin" property of the "options"
// JSON column is set to true
DB::table('users')->where('options->isAdmin', true)->get();
        
// Update all records, setting the "verified" property
// of the "options" JSON column to true
DB::table('users')->update(['options->isVerified', true]);
Previous原生SQLNext事务

Last updated 5 years ago

Was this helpful?