很奇怪的一个赋值问题

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 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
最佳答案

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

这属于对象的可变性,当你每次调用 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年前 评论

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