很奇怪的一个赋值问题

public function index_data(Request $request) {

        $user = $request->user();

        switch($request->type) {
            case 'today' :
                $date = today();
                $query = OrderItem::where('merchant_id', $user->user_merchant->id)->whereDate('created_at', $date);
            break;
            .
            .
            .
        }

        $res['order_count'] = $query->count();
        $res['sell_amount_count'] = $query->sum('item_real_price');
        $res['use_count'] = $query->where('use_status', 5)->count();
        $res['use_amount_count'] = $query->where('use_status', 5)->sum('item_real_price');
        $res['refund_count'] = $query->where('item_refund_status', 'success')->count();
        $res['refund_amount_count'] = $query->where('item_refund_status', 'success')->sum('item_real_price');

        if($res) {
            return response()->json(['res' => $res],201);
        } else {
            return response()->json(['res' => 'none'],201);
        }
    }

$res['refund_count']$res['refund_amount_count']应该分别是 1 和 3.00 ,但是实际结果都是0

但是,如果我要是把下面这两行删除了,就正常了

 $res['use_count'] = $query->where('use_status', 5)->count();

 $res['use_amount_count'] = $query->where('use_status', 5)->sum('item_real_price');

或者,我修改一下,直接写成:

$res['refund_count'] = OrderItem::where('merchant_id', $user->user_merchant->id)->whereDate('created_at', $date)->where('item_refund_status', 'success')->count();

$res['refund_amount_count'] = OrderItem::where('merchant_id', $user->user_merchant->id)->whereDate('created_at', $date)->where('item_refund_status', 'success')->sum('item_real_price');

这是什么情况,不应该会覆盖吧

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
最佳答案

这并不奇怪,而且是完全符合预期的。

这属于对象的可变性,当你每次调用 where 方法的时候,就会往 Builder 对象上的 where 属性添加一条记录,来记录你的 where 条件。

每个 where 都是返回的当前的 Builder 对象($this),所以当你后面的 where 条件,也会影响到你前面保存的 $query ,因为他们本就是指向的同一个对象,这也就是对象的可变性。

如果你想要达到你期待的效果,那你可以使用 clone 语法克隆当前的 Builder,或者调用 Builder 上面的 clone 方法。

$res['order_count'] = $query->count();
$res['sell_amount_count'] = $query->sum('item_real_price');

$useQuery = $query->clone()->where('use_status', 5);
$res['use_count'] = $useQuery->count();
$res['use_amount_count'] = $useQuery->sum('item_real_price');

$refundQuery = $query->clone()->where('item_refund_status', 'success');
$res['refund_count'] = $refundQuery->count();
$res['refund_amount_count'] = $refundQuery->sum('item_real_price');


// 或者使用 clone 语句

$res['order_count'] = $query->count();
$res['sell_amount_count'] = $query->sum('item_real_price');

$useQuery = (clone $query)->where('use_status', 5);
$res['use_count'] = $useQuery->count();
$res['use_amount_count'] = $useQuery->sum('item_real_price');

$refundQuery = (clone $query)->where('item_refund_status', 'success');
$res['refund_count'] = $refundQuery->count();
$res['refund_amount_count'] = $refundQuery->sum('item_real_price');

基于这个特性,在大多数情况下,以下的代码是可以被简化的,你不必将操作的返回值再赋值给 $query,因为他始终都是那一个对象

if($paid){
-    $query = $query->where('paid', 1);
+    $query->where('paid', 1);
}

if($refund){
-    $query = $query->where('refund', 1);
+    $query->where('refund', 1);
}

补充一下吧

把其他的代码去掉后,查询的时候 Builder 大致就是这个样子。

<?php

class Builder
{
    public $where = [];

    public function where(...$args)
    {
        $this->where[] = $args;
    }

    public function count()
    {
        return count($this->where);
    }
}


$builder = new Builder;

$builder->where(1);
$a = $builder->count(); // 1

$builder->where(1);
$b = $builder->count(); // 2

var_dump($b, $builder->where);

// ---------

$builder1 = new Builder;

$c = $builder1->where(1)->count(); // 1
$d = $builder1->where(1)->count(); // 2

var_dump($c, $d, $builder1);

因为他们自始至终都是操作的一个对象。

1年前 评论
wongvio (楼主) 1年前
Rache1 (作者) 1年前
讨论数量: 9

这并不奇怪,而且是完全符合预期的。

这属于对象的可变性,当你每次调用 where 方法的时候,就会往 Builder 对象上的 where 属性添加一条记录,来记录你的 where 条件。

每个 where 都是返回的当前的 Builder 对象($this),所以当你后面的 where 条件,也会影响到你前面保存的 $query ,因为他们本就是指向的同一个对象,这也就是对象的可变性。

如果你想要达到你期待的效果,那你可以使用 clone 语法克隆当前的 Builder,或者调用 Builder 上面的 clone 方法。

$res['order_count'] = $query->count();
$res['sell_amount_count'] = $query->sum('item_real_price');

$useQuery = $query->clone()->where('use_status', 5);
$res['use_count'] = $useQuery->count();
$res['use_amount_count'] = $useQuery->sum('item_real_price');

$refundQuery = $query->clone()->where('item_refund_status', 'success');
$res['refund_count'] = $refundQuery->count();
$res['refund_amount_count'] = $refundQuery->sum('item_real_price');


// 或者使用 clone 语句

$res['order_count'] = $query->count();
$res['sell_amount_count'] = $query->sum('item_real_price');

$useQuery = (clone $query)->where('use_status', 5);
$res['use_count'] = $useQuery->count();
$res['use_amount_count'] = $useQuery->sum('item_real_price');

$refundQuery = (clone $query)->where('item_refund_status', 'success');
$res['refund_count'] = $refundQuery->count();
$res['refund_amount_count'] = $refundQuery->sum('item_real_price');

基于这个特性,在大多数情况下,以下的代码是可以被简化的,你不必将操作的返回值再赋值给 $query,因为他始终都是那一个对象

if($paid){
-    $query = $query->where('paid', 1);
+    $query->where('paid', 1);
}

if($refund){
-    $query = $query->where('refund', 1);
+    $query->where('refund', 1);
}

补充一下吧

把其他的代码去掉后,查询的时候 Builder 大致就是这个样子。

<?php

class Builder
{
    public $where = [];

    public function where(...$args)
    {
        $this->where[] = $args;
    }

    public function count()
    {
        return count($this->where);
    }
}


$builder = new Builder;

$builder->where(1);
$a = $builder->count(); // 1

$builder->where(1);
$b = $builder->count(); // 2

var_dump($b, $builder->where);

// ---------

$builder1 = new Builder;

$c = $builder1->where(1)->count(); // 1
$d = $builder1->where(1)->count(); // 2

var_dump($c, $d, $builder1);

因为他们自始至终都是操作的一个对象。

1年前 评论
wongvio (楼主) 1年前
Rache1 (作者) 1年前

这并不奇怪,而且是完全符合预期的。

这属于对象的可变性,当你每次调用 where 方法的时候,就会往 Builder 对象上的 where 属性添加一条记录,来记录你的 where 条件。

每个 where 都是返回的当前的 Builder 对象($this),所以当你后面的 where 条件,也会影响到你前面保存的 $query ,因为他们本就是指向的同一个对象,这也就是对象的可变性。

如果你想要达到你期待的效果,那你可以使用 clone 语法克隆当前的 Builder,或者调用 Builder 上面的 clone 方法。

$res['order_count'] = $query->count();
$res['sell_amount_count'] = $query->sum('item_real_price');

$useQuery = $query->clone()->where('use_status', 5);
$res['use_count'] = $useQuery->count();
$res['use_amount_count'] = $useQuery->sum('item_real_price');

$refundQuery = $query->clone()->where('item_refund_status', 'success');
$res['refund_count'] = $refundQuery->count();
$res['refund_amount_count'] = $refundQuery->sum('item_real_price');


// 或者使用 clone 语句

$res['order_count'] = $query->count();
$res['sell_amount_count'] = $query->sum('item_real_price');

$useQuery = (clone $query)->where('use_status', 5);
$res['use_count'] = $useQuery->count();
$res['use_amount_count'] = $useQuery->sum('item_real_price');

$refundQuery = (clone $query)->where('item_refund_status', 'success');
$res['refund_count'] = $refundQuery->count();
$res['refund_amount_count'] = $refundQuery->sum('item_real_price');

基于这个特性,在大多数情况下,以下的代码是可以被简化的,你不必将操作的返回值再赋值给 $query,因为他始终都是那一个对象

if($paid){
-    $query = $query->where('paid', 1);
+    $query->where('paid', 1);
}

if($refund){
-    $query = $query->where('refund', 1);
+    $query->where('refund', 1);
}

补充一下吧

把其他的代码去掉后,查询的时候 Builder 大致就是这个样子。

<?php

class Builder
{
    public $where = [];

    public function where(...$args)
    {
        $this->where[] = $args;
    }

    public function count()
    {
        return count($this->where);
    }
}


$builder = new Builder;

$builder->where(1);
$a = $builder->count(); // 1

$builder->where(1);
$b = $builder->count(); // 2

var_dump($b, $builder->where);

// ---------

$builder1 = new Builder;

$c = $builder1->where(1)->count(); // 1
$d = $builder1->where(1)->count(); // 2

var_dump($c, $d, $builder1);

因为他们自始至终都是操作的一个对象。

1年前 评论
wongvio (楼主) 1年前
Rache1 (作者) 1年前

因为上面最终语句: where xxxx and use_status=5 and item_refund_status= ‘succss’ 。
你下面改的就没有use_status=5这个条件了

1年前 评论
wongvio (楼主) 1年前

还可以写一个公共的返回Builder对象的方法。 给大家展示下我的类似代码。 需求是分页展示订单,但是需要同时返回满足条件的总订单,总金额,总杯数(这个需要查另一张表)

 private function get_request_query(Request $request, &$arr = null)
    {
        if ($arr == null) {
            $arr = Orders::query();
        }

        $arr->where('type', 40);
        //  $arr = $arr->orderByDesc('spu_id')->orderByDesc('is_default');

        // $s_input_name=$request->input('s_input_name');
        $s_input_id = $request->input('s_input_id');
        $s_input_order_no = $request->input('s_input_order_no');
        $s_input_pickup_code = $request->input('s_input_pickup_code');
        $s_input_start_date = $request->input('s_input_start_date');
        $s_input_end_date = $request->input('s_input_end_date');
        $s_input_status = $request->input('s_input_status');
        $s_input_phone = $request->input('s_input_phone');
        $s_input_hidden_not_pay = $request->input('s_input_hidden_not_pay');
        $s_input_product_name = $request->input('s_input_product_name');


//        if ($s_input_name){
//            $arr->where('shop_name','like','%'.$s_input_name.'%');
//        }
        if ($s_input_id) {
            $arr->where('id', $s_input_id);
        }
        if ($s_input_hidden_not_pay == 1) {
            $arr->where('new_status_drink', '>=', 5);
        }

        if ($s_input_product_name) {
            $arr->whereHas('order_details', function ($query) use ($s_input_product_name) {
                $query->where('item_name', 'like', '%' . $s_input_product_name . '%');
            });
        }


        if ($s_input_order_no) {
            $arr->where('order_no', 'like', '%' . $s_input_order_no . '%');
        }

        if ($s_input_pickup_code) {
            $arr->whereHas('appends', function ($query) use ($s_input_pickup_code) {
                $query->where('order_key', 'pickup_code')
                    ->where('order_value', $s_input_pickup_code);
            });
        }

        if ($s_input_phone) {
            $arr->whereHas('user', function ($query) use ($s_input_phone) {
                $query->where('user_phone', $s_input_phone);

            });
        }


        if ($s_input_start_date) {
            $arr->where('created_at', '>=', $s_input_start_date . ' 00:00:00');
        }
        if ($s_input_end_date) {
            $arr->where('created_at', '<=', $s_input_end_date . ' 23:59:00');
        }

        if ($s_input_status) {
            $arr->whereIn('new_status_drink', $this->input_status_to_sql($s_input_status));
        }
        return $arr;
    }
    public function query(Request $request)
    {
        $arr = $this->get_request_query($request);
        $list = $arr->orderByDesc('id')->paginate(10);
        $temp = $list->toJson();
        $temp = json_decode($temp, 1);
        $new = [];

        foreach ($list as $v) {
            $result = new ResourceOrderConsumer($v);
            if ($result) {
                $new[] = $result;
            }
        }
        $temp['page'] = $temp['current_page'];
        $temp['perPage'] = $temp['per_page'];

        $temp['items'] = $new;


        unset($temp['data']);
        unset($temp['links']);
        unset($temp['per_page']);
        unset($temp['current_page']);
        unset($temp['first_page_url']);
        unset($temp['last_page_url']);
        unset($temp['next_page_url']);
        unset($temp['path']);
        unset($temp['preview_page_url']);
        unset($temp['from']);
        unset($temp['to']);

        $arr = $this->get_request_query($request);
        $sum = $arr->sum('money');
        $arr = $this->get_request_query($request);
        $sum2 = $arr->count();

        $sum3 = $this->query_all_cup_count($request);

        $temp['total_text'] = '';
        if ($sum2) {
            $temp['total_text'] = '总金额:' . $sum . ",总单数:" . $sum2 . ",总杯数:" . $sum3 . ";
        }
        return output_success($temp);
    }
1年前 评论
yyy123456 (作者) 1年前

提前clone 个query 最后两行的代码 用clone的这个query就行了

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!