上次干这事已经是一年前了,之前的做法特别的繁琐、冗余,具体就是创建一个自定义 Builder 类,继承自 Query\Builder,然后覆盖 Connection 里面获取 Builder 的方法,返回自定义的 Builder,还有其他一系列很长的步骤。

下面是之前的做法:

(算了,还是不说了,太蠢),总之,多看看源码有好处

就说最优雅的解决方法吧:

laravel 中提供了 Macroable 的 trait,之前一直没有想过可以用上这个东西。

最近才想到可以这么做,源码看这里:https://github.com/laravel/framework/blob/5.6/src/Illuminate/Support/Traits/Macroable.php

目前用的是 5.1 版本,应该 5.1 版本以后的都有这个特性。

当然,你也可以在 Model 基类里面添加自定义方法,但是这样添加的方法 DB 类是用不了的。

但是使用 macro 定义到 Builder 的方法可以同时在 DB 类和 Eloquent Model 中使用(具体不赘述,自己看源码,就是利用 __call、__callStatic 这些魔术方法)。

使用方法:调用 Macroable 的 macro 方法,绑定一个自定义方法到 Builder 类中,如:

\Illuminate\Database\Query\Builder\Builder::macro('active', function () {
return $this->where('status', 1);
});

  

调用方法是(使用 DB 类):

DB::table(xxx)->active()->get();

  

或者(使用 Eloquent Model):

\App\Model\User::active()->first();

  

至于我们应该把上面那几行放哪里?

个人觉得一个比较好的地方是 Providers 中,在 app/Providers 下面新建一个 Provider,把 macro 调用放到 Provider 的 register 方法中。如:

<?php

namespace App\Providers;

use Illuminate\Database\Query\Builder;
use Illuminate\Support\ServiceProvider; /** @mixin \Illuminate\Database\Eloquent\Builder */
class DatabaseServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
Builder::macro('active', function () {
return $this->where('status', 1);
});
}
}

  

当然,加了 Providers 之后还要在 config/app.php 中配置这个 Provider。

就这样。

还有个问题是,这样添加的方法 ide 无法识别,我们这时候就可以使用 @method 了,如:

@method $this active()

可以使用命令把这些 @method 写入到 Builder 头部(我看 laravel-ide-helper 这么干我才这么干的):

<?php

namespace App\Console\Utils;

use App\Console\Commands\BaseCommand;

/** @see \Illuminate\Database\Query\Builder */
class Ide extends BaseCommand
{
public $signature = 'ide'; public $description = '生成 PHP doc到 Query Builder'; public function handle()
{
$file = base_path() . '/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php';
if (!is_file($file)) {
$this->info("文件不存在({$file}), 先 composer install");
return;
} $content = file_get_contents($file);
$pos = strpos($content, 'class Builder');
list($before, $after) = $this->splitFileByPos($content, $pos);
$before = $this->removeOldDoc($before);
$new_file_content = $before . $this->docProvider() . $after; $f = fopen($file, 'w+');
fwrite($f, $new_file_content);
fclose($f);
} // 移除旧的 php doc
private function removeOldDoc($before)
{
if (preg_match('/(\/\*.*?\*\/)/ism', $before, $match)) {
$before = preg_replace('/(\/\*.*?\*\/)/ism', '', $before);
} return $before;
} // 生成新的 php doc
private function docProvider()
{
return <<<DOC
/**
* @method \$this like(\$field, \$keyword = '')
* @method \$this recent()
* @method \$this active()
* @method \$this notDeleted()
*/\n
DOC;
} // 通过一个点把文件分割成两部分
private function splitFileByPos($content_string, $pos)
{
$before = substr($content_string, 0, $pos);
$after = substr($content_string, $pos); return [$before, $after];
}
}

  

这样的好处是,也没什么好处,就是你 push 上去的时候,一般 vendor 都 ignore 了,在其他电脑 clone 下来,就没有那些 @method 了,也就不会有语法提示了。

手速惊人的还是忽略吧。

  

laravel query builder/ Eloquent builder 添加自定义方法的更多相关文章

  1. Laravel Query Builder 复杂查询案例:子查询实现分区查询 partition by

    案例 案例:Laravel 在文章列表中附带上前10条评论?,在获取文章列表时同时把每个文章的前10条评论一同查询出来. 这是典型分区查询案例,需要根据 comments 表中的 post_id 字段 ...

  2. [Laravel] 16 - DB: Eloquent

    前言 一.大纲 写后端API,与数据库打交道无疑是很重要的角色. PHP数据库操作:从MySQL原生API到PDO PHP数据库操作:使用ORM Ref: [PHP] 07 - Json, XML a ...

  3. [转]Laravel 4之Eloquent ORM

    Laravel 4之Eloquent ORM http://dingjiannan.com/2013/laravel-eloquent/ 定义Eloquent模型 模型通常放在app/models目录 ...

  4. 【Laravel】为Eloquent 模型设置全局作用域和局部作用域进行查询

    全局作用域 所谓「全局作用域」,指的是预置过滤器在注册该「全局作用域」的模型类的所有查询中生效,不需要指定任何额外条件. 以 User 模型类为例,我们在系统中可能只想针对已经验证过邮箱的用户进行操作 ...

  5. 十六、springboot整合Spring-data-jpa(二)之通用DAO接口与添加自定义方法

    @NoRepositoryBean:Spring Data Jpa在启动时就不会去实例化BaseRepository这个接口 1.通用接口: import org.springframework.da ...

  6. Actionscript,AS3,MXML,Flex,Flex Builder,Flash Builder,Flash,AIR,Flash Player之关系

    转自zrong's blog:http://zengrong.net/post/1295.htm ActionScript ActionScript通常简称为AS,它是Flash平台的语言.AS编写的 ...

  7. (十三)SpringBoot之Spring-Data-Jpa(二)CRUD实现以及添加自定义方法

    一.jpa中添加自定义方法 http://blog.csdn.net/qq_23660243/article/details/43194465 二.案例 1.3 引入jpa依赖 <depende ...

  8. 3.2Adding custom methods to mappers(在映射器中添加自定义方法)

    3.2Adding custom methods to mappers(在映射器中添加自定义方法) 有些情况下,我们需要实现一些MapStruct无法直接自动生成的复杂类型间映射.一种方式是复用其他已 ...

  9. [Laravel] 03 - DB facade, Query builder & Eloquent ORM

    连接数据库 一.Outline 三种操作数据库的方式. 二.Facade(外观)模式 Ref: 解读Laravel,看PHP如何实现Facade? Facade本质上是一个“把工作推给别人做的”的类. ...

随机推荐

  1. 239. [LeetCode ]Sliding Window Maximum

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  2. Logistic回归 逻辑回归 练习——以2018建模校赛为数据源

    把上次建模校赛一个根据三围将女性分为四类(苹果型.梨形.报纸型.沙漏)的问题用逻辑回归实现了,包括从excel读取数据等一系列操作. Excel的格式如下:假设有r列,则前r-1列为数据,最后一列为类 ...

  3. JavaScript 高级之面向对象

    1. 对象属性及方法 创建对象的方式 <script> //创建对象的方式一 var obj = {}; //创建对象的方式一 var obj = new Object(); </s ...

  4. Linux发行版本应用场景

    如果你是一个Linux爱好者,想选择一个桌面系统,并且既不想用盗版,又不想花太多钱购买商业系统软件,那么可以选择Ubuntu桌面系统.如果你需要服务器端的Linux系统,想用一个比较稳定的服务器系统, ...

  5. Spring+Netty4实现的简单通信框架

    参考:http://cpjsjxy.iteye.com/blog/1587601 Spring+Netty4实现的简单通信框架,支持Socket.HTTP.WebSocket_Text.WebSock ...

  6. 软工alpha阶段个人总结

    一.个人总结 类别 具体技能和面试问题 现在的回答(大三下) 语言 最拿手的语言之一,代码量是多少? java,代码量在一万行左右 语言 最拿手的语言之二,代码量是多少? C语言,代码量在五千行左右 ...

  7. Centos7更改默认启动桌面(或命令行)模式

    centos7以后是这样的,7以前就是别的版本了 1.systemctl get-default命令获取当前模式 2.systemctl set-default graphical.target 修改 ...

  8. 把握曝光三要素(上):快门、光圈、ISO

    概要: 如果你还没有掌握快门.光圈和ISO,那这篇文章或许对你有所帮助! 把照片比作水池.把进光量比作水.把快门比作关闭水龙头的速度.把光圈比作水龙头的大小.把感光度ISO比作水龙头的滤网,这就变得好 ...

  9. python接口自动化测试框架实现之字符串插入变量(字符串参数化)

    问题: 在做接口自动化测试的时候,请求报文是json串,但是根据项目规则必须转换成字符串,然后在开头拼接“data=” 接口中很多入参值需要进行参数化. 解决方案: 1.Python并没有对在字符串中 ...

  10. virtio 之后的数据直连

    在上一篇中说了virtio这种半虚拟化方案之后,还有一种全虚拟化的方案,这种全虚拟化的方案中,直接宿主机上的设备,直接被虚拟化成了n个设备,然后这些设备可以直接被加载进guest os中当做一个普通的 ...