【问题标题】:Laravel4 query cloningLaravel4 查询克隆
【发布时间】:2015-03-03 12:23:46
【问题描述】:

这个问题快把我逼疯了。
自我上次更新作曲家以来,克隆查询似乎无法按预期工作。
奇怪的是,如果我不在第一个查询克隆上执行->get(),第二个查询执行得很好。从我对两个查询克隆执行->get的那一刻起,我收到一个错误: General error: 2031 clone 应该创建原始查询的深层副本,但似乎有些不对劲。
有任何想法吗?这是我的查询(看起来比实际复杂,查询本身很好):

    //Query dates 
    $query_onetime = clone $query; 
    $query_onetime = $query_onetime->join('events_dates', function($join) use ($input_date_start, $input_date_end){ 
                $join->on('events.id', '=', 'events_dates.event_id'); 
                    $join->where('events_dates.start_date', "<=", $input_date_end); 
                    $join->where('events_dates.end_date', '>=', $input_date_start); 
            }); 

    //Select fields 
    $events_onetime = $query_onetime->select('events.id AS id', 'events.name AS name', 'event_categories.id as category_id', 'event_categories.category as category', 
                    'event_subcategories.id as subcategory_id', 'event_subcategories.subcategory as subcategory', 
                    'short_description', 'time_description', 
                    'price_description', 'nr_going', 'nr_checkedin', 'homepage', 'fbpage', 'profile_pic', 
                    'places.id AS place_id', 'places.name AS place_name', 'lat', 'lng', 'address')
            ->groupBy('events.id')
            ->get(); 

    if(isset($data["include_recurrent"]) && $data["include_recurrent"]){ 

        //Query recurrent dates 
        $query_recurrent = clone $query; 
        $query_recurrent = $query_recurrent->join('events_dates_recurrent', 'events.id', '=', 'events_dates_recurrent.event_id')
            ->where(function($join) use ($input_date_start, $input_date_end) { 
                //Create a dynamic query to get all recurrent dates within the input time interval 
                $query_string = "ABS(DATEDIFF('" . $input_date_start . "', CAST(events_dates_recurrent.start_date AS DATE)) % events_dates_recurrent.repeat_interval) = 0"; 
                $temp_date_start = $input_date_start; 

                while(strtotime($temp_date_start) < strtotime($input_date_end)){ 
                    $temp_date_start = date('Y-m-d', strtotime($temp_date_start . " +1 day")); 
                    //Create a raw query string 
                    $query_string = $query_string . " OR ABS(DATEDIFF('" . $temp_date_start . "', CAST(events_dates_recurrent.start_date AS DATE)) % events_dates_recurrent.repeat_interval) = 0"; 
                } 
                $join->whereRaw($query_string); 
            }); 

        //Select fields 
        $events_recurrent = $query_recurrent->select('events.id AS id', 'events.name AS name', 'event_categories.id as category_id', 'event_categories.category as category', 
                        'event_subcategories.id as subcategory_id', 'event_subcategories.subcategory as subcategory', 
                        'short_description', 'time_description', 
                        'price_description', 'nr_going', 'nr_checkedin', 'homepage', 'fbpage', 'profile_pic', 
                        'places.id AS place_id', 'places.name AS place_name', 'lat', 'lng', 'address')
                ->groupBy('events.id')
                ->get(); 

        $events = array_merge($events_onetime, $events_recurrent); 

编辑:有关请求的信息,这里是完整的查询。
我避开了它,因为它很长。

    // Queries events based on map bounds, category and date 
    $query = DB::table('events')
            ->join('places', function($join) use ($data){ 
                $join->on('events.place_id', '=', 'places.id')
                        ->where('places.lat', '>', $data['sw_lat'])
                        ->where('places.lat', '<', $data['ne_lat'])
                        ->where('places.lng', '>', $data['sw_lng'])
                        ->where('places.lng', '<', $data['ne_lng']); 
            })->join('event_categories', function($join) use ($data){ 
                $join->on('events.category_id', '=', 'event_categories.id'); 
            }); 

    // The category id is optional 
    if(isset($data["category_id"])){ 
        $query = $query->where('event_categories.id', '=', $data['category_id']);  
    } 
    //Query subcategory 
    $query = $query->leftJoin('event_subcategories', function($join) use ($data){ 
                $join->on('events.subcategory_id', "=", "event_subcategories.id"); 
            }); 

    //Query keywords 
    $query = $query->join('events_keywords', 'events.id', '=', 'events_keywords.event_id'); 

    //Reverse date format 
    $input_date_start = date("Y-m-d", strtotime($data["date_start"])); 
    $input_date_end = date("Y-m-d", strtotime($data["date_end"])); 

    //Query dates 
    $query_onetime = clone $query; 
    $query_onetime = $query_onetime->join('events_dates', function($join) use ($input_date_start, $input_date_end){ 
                $join->on('events.id', '=', 'events_dates.event_id'); 
                    $join->where('events_dates.start_date', "<=", $input_date_end); 
                    $join->where('events_dates.end_date', '>=', $input_date_start); 
            }); 
    //Select fields 
    $events_onetime = $query_onetime->select('events.id AS id', 'events.name AS name', 'event_categories.id as category_id', 'event_categories.category as category', 
                    'event_subcategories.id as subcategory_id', 'event_subcategories.subcategory as subcategory', 
                    'short_description', 'time_description', 
                    'price_description', 'nr_going', 'nr_checkedin', 'homepage', 'fbpage', 'profile_pic', 
                    'places.id AS place_id', 'places.name AS place_name', 'lat', 'lng', 'address')
            ->groupBy('events.id')
            ->get(); 

    foreach($events_onetime as $event){ 
        $temp_event = EventModel::find($event->id); 
        $event->keywords = $temp_event->keywords; 
    } 

    if(isset($data["include_recurrent"]) && $data["include_recurrent"]){ 

        //Query recurrent dates 
        $query_recurrent = clone $query; 
        $query_recurrent = $query_recurrent->join('events_dates_recurrent', 'events.id', '=', 'events_dates_recurrent.event_id')
            ->where(function($join) use ($input_date_start, $input_date_end) { 
                //Create a dynamic query to get all recurrent dates within the input time interval 
                $query_string = "ABS(DATEDIFF('" . $input_date_start . "', CAST(events_dates_recurrent.start_date AS DATE)) % events_dates_recurrent.repeat_interval) = 0"; 
                $temp_date_start = $input_date_start; 

                while(strtotime($temp_date_start) < strtotime($input_date_end)){ 
                    $temp_date_start = date('Y-m-d', strtotime($temp_date_start . " +1 day")); 
                    //Create a raw query string 
                    $query_string = $query_string . " OR ABS(DATEDIFF('" . $temp_date_start . "', CAST(events_dates_recurrent.start_date AS DATE)) % events_dates_recurrent.repeat_interval) = 0"; 
                } 
                $join->whereRaw($query_string); 
            }); 

        //Select fields 
        $events_recurrent = $query_recurrent->select('events.id AS id', 'events.name AS name', 'event_categories.id as category_id', 'event_categories.category as category', 
                        'event_subcategories.id as subcategory_id', 'event_subcategories.subcategory as subcategory', 
                        'short_description', 'time_description', 
                        'price_description', 'nr_going', 'nr_checkedin', 'homepage', 'fbpage', 'profile_pic', 
                        'places.id AS place_id', 'places.name AS place_name', 'lat', 'lng', 'address')
                ->groupBy('events.id')
                ->get(); 

        //At this point we just have the events, but we also need the keywords per event. 
        foreach($events_recurrent as $event){ 
            $temp_event = EventModel::find($event->id); 
            $event->keywords = $temp_event->keywords; 
        } 
        $events = array_merge($events_onetime, $events_recurrent); 
    } else { 
        //Else return only the non-recurrent events 
        $events = $events_onetime; 
    }

    return $events; 
} 

【问题讨论】:

  • 一开始你克隆$query两次怎么样? $query_onetime = clone $query; $query_recurrent = clone $query;
  • 不走运...最终得到相同的结果。奇怪的是,如果我不能同时进入两者之一,那么它对任何一个都有效。但我必须结合这两个查询的结果。
  • 你能告诉我$query 是什么吗?顺便说一句,MySQL 错误 2031 似乎与绑定参数有关。
  • 您可能需要重新考虑“查询范围”,使其更易于维护和阅读。
  • @KimGysen 幸运的是,Laravel 让这一切变得超级简单 :) laravel.com/docs/4.2/eloquent#query-scopes 你只需将相关查询逻辑块组织到模型上的一个方法中,并在实现它们时将它们链接在一起,@ 987654331@

标签: php laravel-4 clone


【解决方案1】:

您的$query 对象是Illuminate\Database\Eloquent\Builder 的一个实例,它维护着对包含实际查询的Illuminate\Database\Query\Builder 的引用。根据PHP Docsclone 关键字执行对象的浅拷贝,这意味着引用被复制为引用。因此,$query$query_onetime 都保持对同一个 Illuminate\Database\Query\Builder 实例的引用,并且对其中一个实例的更改会影响另一个。

这个需要克隆底层查询的问题已在 Laravel 4.1 中修复,但如果您不想升级,可以尝试以下解决方法:

$query_onetime = clone $query;
$query_onetime->setQuery(clone $query->getQuery());
// Any additional joins specific to $query_onetime

【讨论】:

  • 谢谢,原来如此。我收到一个错误,提到Call to undefined method Illuminate\Database\Query\Builder::getQuery()。知道可能是什么原因吗?
  • 你使用的是什么版本的 Laravel?
  • @BrokenBinary 仔细看看这个问题。 OP 没有使用 Eloquent。
  • 返回get_class($query)时,我收到Illuminate\Database\Query\Builder。版本是4.2.16。
  • 这个问题应该在 4.1 中得到修复,正如@lukasgeiter 提到的,你没有像我想象的那样使用 Eloquent。我回答的问题不是你遇到的问题。
猜你喜欢
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2023-02-02
  • 1970-01-01
  • 2015-03-12
  • 2019-04-24
  • 1970-01-01
  • 2012-11-21
相关资源
最近更新 更多