This problem is driving me nuts.
It appears that cloning a query doesn't work as expected since my last composer update.
The weird thing is that if I don't perform ->get()on the first query clone, the second query executes fine. From the moment I perform the ->geton both query clones, I receive an error:
General error: 2031
The clone should create a deep copy of the original query, but something doesn't seem right.
Any ideas? Here is my query (it looks more complex than it is, and the query itself is fine):
//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);
EDIT: for info on request, here is the full query.
I avoided it because it is pretty long.
// 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;
}
Your $query object is an instance of Illuminate\Database\Eloquent\Builder and it maintains a reference to a Illuminate\Database\Query\Builder which holds the actual query. According to the PHP Docs, the clone keyword performs a shallow copy of an object, meaning that references are copied as references. Thus, $query and $query_onetime both maintain a reference to the same Illuminate\Database\Query\Builder instance and changes to one affect the other.
This issue with needing to clone the underlying query has been fixed in Laravel 4.1, but if you don't want to upgrade you can try this workaround:
$query_onetime = clone $query;
$query_onetime->setQuery(clone $query->getQuery());
// Any additional joins specific to $query_onetime
Related
How to Assign or store Model's table name into a variable in laravel (this is for filter functionality)?
$query = new LiveClasses;
if (request('language')) {
// die("333");
$query->where('language_used', '=', request('language'));
}
if (request('start') && request('last')) {
// die("333");
$first = 'sub_price_1 >= ' . request('start');
$second = 'sub_price_1 <= ' . request('last');
$query->whereRaw($first)->whereRaw($second);
}
if (request('rating')) {
// die("&rating=5&start=150&last=1264");
$query
->leftJoin('reviews', 'reviews.reviewable_id', '=', 'live_classes.id')
->Where('rating', request('rating'))
->Where('reviewable_type', '=', 'App\Models\LiveClasses');
// $courses = Review::where('rating', request('rating'))
// ->leftJoin('live_classes', 'reviews.reviewable_id', '=', 'live_classes.id')
}
$courses = $query->paginate(9);
To get the name of model table use ->getTable() eloquent method.
To get the morphable class name (type) use ->getMorphClass() eloquent method.
$query = new LiveClasses;
if (request('language')) {
$query->where('language_used', '=', request('language'));
}
if (request('start') && request('last')) {
$first = 'sub_price_1 >= ' . request('start');
$second = 'sub_price_1 <= ' . request('last');
$query->whereRaw($first)->whereRaw($second);
}
if (request('rating')) {
$reviewTable = (new Review)->getTable();
$query
->leftJoin($reviewTable, reviewTable . '.reviewable_id', '=', $query->getTable() . '.id')
->where('rating', request('rating'))
->where('reviewable_type', '=', $query->getMorphClass());
}
$courses = $query->paginate(9);
I use this query and i get a error :
$description = $request->get('description');
if (!empty($description)){
$description_query = Transcationhistorique::where(['sender_id' => $user_id, "%$description%", 'LIKE','description'])
->orWhere('receiver_id', $user_id)->get();
}else{
$description_query = "" ;
}
and this is the error that I get :
"SQLSTATE[42S22]: Column not found: 1054 Unknown column '0' in 'where
clause' (SQL: select * from transcation_historique where
(sender_id = 32 and 0 = %salaire% and 1 = LIKE and 2 =
description) or receiver_id = 32)"
and this what really i want to run:
select * from `transcation_historique` where (`sender_id` = 32 and `description` = %salaire%) or `receiver_id` = 32)
Try this,
$description_query = Transcationhistorique::where(
function($query) use ($user_id, $description){
return $query->where('sender_id', $user_id)
->where('description', 'like', '%' . $description .'%');
}
)
->orWhere('receiver_id', $user_id)
->get();
It seems like your where query is not structured correctly.
You should use the following structure if you want to use operators other than "="
Source
$query->where([
['column_1', '=', 'value_1'],
['column_2', '<>', 'value_2'],
[COLUMN, OPERATOR, VALUE],
...
])
My suggestion is:
$description = $request->get('description');
if (!empty($description)){
$description_query = Transcationhistorique::where([
['sender_id', '=', $user_id],
['description', 'LIKE', "%{$description}%"]
])
->orWhere('receiver_id', $user_id)->get();
}else{
$description_query = "" ;
}
Try this one:
Transcationhistorique::where('receiver_id', '=', $user_id)
->orWhere(function ($query) use ($user_id, $description) {
$query->where('sender_id', '=', $user_id)->where('description', 'LIKE', "%".$description."%");
})->get();
You can use multiple where method as and.
Can you try following codes?
$description = $request->get('description');
if (!empty($description)){
$description_query = Transcationhistorique::where('sender_id', $user_id)
->where("description", 'LIKE','%' . $description . '%')
->orWhere('receiver_id', $user_id)->get();
}else{
$description_query = "" ;
}
How to convert this code to Laravel (Eloquent):
$query = 'SELECT * FROM posts p WHERE (p.is_public = 1)';
if (isset($date)){ //$date format is '2018-09-01 00:00:00'
$query .= ' AND (p.created_at > "'.$date.'")';
}
if (isset($search)){
$query .= ' AND ((p.title LIKE "%'.$search.'%") OR (p.body LIKE "%'.$search.'%"))';
}
try this:
assume Post is your model
$posts = Post::where('is_public', 1);
if (isset($date)) {
$posts->where('created_at', '>', $date);
}
if (isset($search)) {
$posts->where(function($query) use ($search) {
$query->where('title', 'like', "%'.$search.'%")
->orWhere('body', 'like', "%'.$search.'%");
});
}
$posts = $posts->get();
This is Example code : assume Post is your model
$getPosts=Post::query()->where('is_public',1);
$getPosts->when(isset($date),function($q) use ($date){
$q->where('created_at','>',$date);
});
$getPosts->when(isset($search),function($q) use ($search){
$q->where('title','like','%'.$search.'%');
$q->orWhere('body','like','%'.$search.'%');
});
$posts=$getPosts->get();
You should try this:
$query = Post::where('is_public', '1');
if (isset($date)){ //$date format is '2018-09-01 00:00:00'
$query->where('created_at', '>', $date);
}
if (isset($search)){
$query->whereRaw('title LIKE "%'.$search.'%" OR body LIKE "%'.$search.'%"');
}
$posts = $query->get();
I am new to PHP and new to Laravel. I'm taking over an old project.
We had this code and it was working fine:
public function getList(Request $request)
{
$apiFormat = array();
try
{
$perPage = Input::get('page_size', 10);
$filters = $request->input();
$postRepo = new PostRepo();
$user = $_SESSION["user"];
$listPost = $postRepo->getlist($user->id, $perPage, 0);
$apiFormat['status'] =\Config::get('constants.api.STATUS_OK');
$apiFormat['message'] = \Config::get('constants.api.SUCCESS');
$apiFormat['data'] = $listPost;
} catch (\Exception $ex) {
$apiFormat['status'] =
\Config::get('constants.api.STATUS_ERROR');
$apiFormat['message'] = $ex->getMessage();
}
return response()->json($apiFormat);
}
This returned 10 items that would show up on our newsfeed.
This line:
$listPost = $postRepo->getlist($user->id, $perPage, 0);
Did a database call like this:
$sqlCheckHasLike = "SELECT count(*) > 0 FROM `likes` WHERE `post_id` = `posts`.`id` and `user_id` = '".$user_id."'";
$query = DB::table('posts')
->select('posts.*',DB::raw("($sqlCheckHasLike) as is_like"), 'users.full_name', 'users.avatar', DB::raw("post_categories.name as post_categories_name"))
->leftJoin('users', 'posts.user_id', '=', 'users.id')
->leftJoin('post_categories', 'post_categories.id', '=', 'posts.post_category_id')
->where('posts.status',$post_status)
->where('users.status', 1)
->where(function ($query) use ($user_id, $list_user) {
$query->whereIn('user_id', $list_user)
->orwhere('user_id', $user_id);
})
->orderBy('created_at', 'desc')->paginate($pageSize);
return $query;
However, we've just added comments to each item in the newsfeed. That code is handled elsewhere, but here I want to find, given a post.id, how many comments belong to it? This needs to be included in the response.
Replacing the first method, I tried this:
try {
$perPage = Input::get('page_size', 10);
$filters = $request->input();
$postRepo = new PostRepo();
$user = $_SESSION["user"];
$listPost = $postRepo->getlist($user->id, $perPage, 0);
$array_of_rows = [];
foreach ($listPost as $lp) {
$row_as_array = (array) $lp;
$post_id = $lp->id;
$query = "select count(id) as how_many from comments where
post_id = '". $post_id ."'";
$result_array = DB::select($query);
$result_obj = $result_array[0];
$how_many = $result_obj->how_many;
$row_as_array['how_many_comments'] = $how_many;
$array_of_rows[] = $row_as_array;
}
$merged_list_post = (object) $array_of_rows;
file_put_contents("/var/log/api_debugging", "\ncomment count:\n",
FILE_APPEND | LOCK_EX);
file_put_contents("/var/log/api_debugging",
print_r($merged_list_post, true), FILE_APPEND | LOCK_EX);
$apiFormat['status'] = \Config::get('constants.api.STATUS_OK');
$apiFormat['message'] = \Config::get('constants.api.SUCCESS');
$apiFormat['data'] = $merged_list_post;
} catch (\Exception $ex) {
$apiFormat['status']=\Config::get('constants.api.STATUS_ERROR');
$apiFormat['message'] = $ex->getMessage();
}
This does not throw an error (there are no Exceptions) but it changed the returned data, such that the apps which consume this feed no longer get what they need.
Is there an official approach in Laravel that makes it easy to do several database queries, and combine that data at a per inner object level? I'd like to avoid returning an object that is of a different type than the one in the original example.
You could just modify the original query (I've just included the first few lines here) to JOIN the comments table and get the count:
$query = DB::table('posts')
->select('posts.*',DB::raw("($sqlCheckHasLike) as is_like"), 'users.full_name', 'users.avatar', DB::raw("post_categories.name as post_categories_name"), DB::raw("count(comments.id) as how_many"))
->leftJoin('users', 'posts.user_id', '=', 'users.id')
->leftJoin('post_categories', 'post_categories.id', '=', 'posts.post_category_id')
->leftJoin('comments', 'comments.post_id', '=', 'posts.id')
You will also need to add a groupBy clause:
->groupBy('posts.id')
prior to the orderBy.
I have situation in laravel 5.1 with eloquent. That is very hard for me at this time to get the solution.
I have 7 tables in database which are not related to each other, but I want to get results with joining them all and with where clause.
My Tables relations are:
lifegroups -> Campuses -> locations -> address
and
lifegroups -> grouptype -> groupuser -> user // this is confusing little bit
and
lifegroups -> schedule -> recurrance
Notice the lifegroup table is associated with multiple other tables.
My Existing Query is:
$campusGroups = DB::table('campuses')
->Join('lifegroups','campuses.f1_id', '=', 'lifegroups.campusId')
->Join('locations', 'locations.group_id', '=', 'lifegroups.f1Id')
->Join('addresses', 'addresses.location_id', '=', 'locations.id')
->Join('groups_users', 'groups_users.groupId', '=', 'lifegroups.id')
->Join('users', 'groups_users.userId', '=', 'users.id')
->distinct() //'users.first_name', 'users.last_name',
->select('lifegroups.*', 'campuses.name AS campusname', 'addresses.address', 'addresses.address2', 'addresses.city', 'addresses.province');
$groupLeaders = DB::table('campuses')
->Join('lifegroups', 'campuses.f1_id', '=', 'lifegroups.campusId')
->Join('groups_users', 'groups_users.groupId', '=', 'lifegroups.id')
->Join('users', 'groups_users.userId', '=', 'users.id')
->distinct()
->select('lifegroups.id', 'users.first_name', 'users.last_name');
$groupRecurrences = DB::table('campuses')
->Join('lifegroups', 'campuses.f1_id', '=', 'lifegroups.campusId')
->Join('schedules', 'schedules.event_id', '=', 'lifegroups.eventid')
->Join('recurrences', 'recurrences.schedule_id', '=', 'schedules.id')
->distinct()
->select('recurrences.occurOnFriday', 'recurrences.occurOnSaturday', 'recurrences.occurOnMonday', 'recurrences.occurOnSunday', 'recurrences.occurOnThursday', 'recurrences.occurOnTuesday', 'recurrences.occurOnWednesday', 'recurrences.recurrenceFrequency', 'recurrences.recurrenceFrequencyMonthly', 'recurrences.recurrenceFrequencyWeekly', 'schedules.start_date', 'schedules.recurrence', 'lifegroups.id AS groupId');
if (Session::has('campus')){
$campusId = Session::get('campus');
$searchObj = $campusGroups->where('campuses.id', intval($campusId));
$groupLeaders = $groupLeaders->where('campuses.id', intval($campusId));
$groupRecurrences = $groupRecurrences->where('campuses.id', intval($campusId));
$searchArray['campusId'] = $campusId;
}
if (Session::has('gender')){
$gender = Session::get('gender');
$searchObj = $campusGroups->where('lifegroups.gender', $gender);
$groupLeaders = $groupLeaders->where('lifegroups.gender', $gender);
$groupRecurrences = $groupRecurrences->where('lifegroups.gender', $gender);
$searchArray['gender'] = $gender;
} else {
$searchArray['gender'] = 'N/A';
}
if (Session::has('marital_status')){
$marital_status = Session::get('marital_status');
$searchObj = $campusGroups->where('lifegroups.marital_status', $marital_status);
$groupLeaders = $groupLeaders->where('lifegroups.marital_status', $marital_status);
$groupRecurrences = $groupRecurrences->where('lifegroups.marital_status', $marital_status);
$searchArray['marital_status'] = $marital_status;
} else {
$searchArray['marital_status'] = 'N/A';
}
if (Session::has('age')){
$age = Session::get('age');
$searchObj = $campusGroups->where('lifegroups.startAgeRange', $age);
$groupLeaders = $groupLeaders->where('lifegroups.startAgeRange', $age);
$groupRecurrences = $groupRecurrences->where('lifegroups.startAgeRange', $age);
$searchArray['age'] = $age;
} else {
$searchArray['age'] = 'N/A';
}
if (Session::has('keyword')){
$keyword = Session::get('keyword');
$searchObj = $campusGroups->where('lifegroups.name', 'Like', '%'. $keyword . '%');
//->orWhere('lifegroups.description', 'Like', '%'.$keyword.'%')
//->orWhere('users.first_name', 'Like', '%'.$keyword.'%');
$groupLeaders = $groupLeaders->where('lifegroups.name', 'Like', '%'. $keyword . '%');
$groupRecurrences = $groupRecurrences->where('lifegroups.name', 'Like', '%'. $keyword . '%');
$searchArray['keyword'] = $keyword;
} else {
$searchArray['keyword'] = 'N/A';
}
$campusGroupsTemp = $campusGroups->get();
$campusGroups = [];
$recurrenceGroups = [];
$groupLeaders = $groupLeaders->get();
$groupRecurrences = $groupRecurrences->get();
So this is a very long process and I can't add further search filters. Do you guys have any better idea how to do it with Laravel Eloquent, like
Lifegroups::with(['campuses', 'locations', 'addresses', 'grouptype', 'groupuser', 'users', 'schedules', 'recurrences'])
->where(['lifegroups.name', '=' 'name_value'],['lifegroups.description','like', '%like_valie%'], ['user.first_name', 'like', 'first_name_value'])
->get()->toArray();
If you are confused like me then only let me know how to do below mentioned thing with above type of tables scenario.
This becomes very easy with Eloquent assuming you have your models setup correctly. Just use dot notation to handle the nesting.
$data = Lifegroups::with([
'campuses.locations.address',
['grouptype.groupuser.user', function($q) use ($first_name) {
// Handle the constraints on the users table here.
$q->where('name', 'like', $first_name)
}],
'schedule.recurrance'
])
// Handle any constraints on the Lifegroups table here
->where('name', '=', 'name_value')
->where('description','like', '%like_valie%')
->get();
If you need to add more constraints for different tables, just add another parameter to the array we passed into the with function going as deep as you need to with the nexting and passing in a function with it where you will set the constraints like I did the users table.