Query builder. Simultaneously Where() and With() methods - laravel-5.8

HTML form contains multiple I send them to the server
$min = $request->input('min');
$max = $request->input('max');
$sort = $request->input('sort');
Sometimes the value of the inputs is empty and for this reason I use query builder:
$q = DB::table('adverts');
if ($request->has('max') && $request->input('max') != ""){
$q->where('price', "<" , $max)->orderBy($col, $way);
}
but if I add ->with('images') I get an error Call to undefined method Illuminate\Database\Query\Builder::with()
if ($request->has('max') && $request->input('max') != ""){
$q->where('price', "<" , $max)->with('images')->orderBy($col, $way);
}

You can not use with() with DB class, with() is applied to Eloquent Builder.
Example: $books = App\Book::with(['author', 'publisher'])->get();.
If you want to use DB builder, you have to use joins to load related data.

Related

Using WhereRaw on collection ignores relation

I made a route to search a particular collection - Customers.
Customer Model
public function location() {
return $this->belongsTo('App\Location');
}
Location Model
public function customers() {
return $this->hasMany('App\Customer');
}
On the index page, I'm simply showing the customers with the data from $location->customers()
$location comes from the model route binding.
This is my search controller:
if ($request->input('search') != null) {
$customers = $location->customers();
$search = strtoupper($request->input('search'));
$searchQuery = 'UPPER(email) LIKE (?) OR CONCAT(UPPER(first_name), " ", UPPER(last_name)) LIKE (?)';
$customers = $location->customers()->whereRaw($searchQuery, ["%{$search}%", "%{$search}%"]);
$customers = $customers->paginate();
}
return response()->json(['results' => $customers], 200);
When a search is executed, I get 10 times as many results in some cases because it's grabbing all customers rather than the specific location relationship.
How can I make whereRaw use the relation?
It is because the OR condition messes up with the query. To avoid that wrap those two query parts with brackets ().
$searchQuery = '( UPPER(email) LIKE (?) OR CONCAT(UPPER(first_name), " ", UPPER(last_name)) LIKE (?) )';
Eloquent builder approach:
$customers = $location->customers()->where(function($query) use ($search) {
$query->whereRaw('UPPER(email) LIKE (?)', ["%{$search}%"]);
$query->orWhereRaw('CONCAT(UPPER(first_name), " ", UPPER(last_name)) LIKE (?)', ["%{$search}%"]);
});
Explanation
Example logical expression:
firstCondition && secondCondition || thirdCondition
In above example expression thirdCondition does not even care about firstCondition or secondCondition because of the ||.
So if you want to check this thirdCondition with secondCondition, then you have to explicitly wrap this two conditions with brackets ().
firstCondition && ( secondCondition || thirdCondition )
This same logic applies for mysql queries too.

How to echo the last query after eloquent model in laravel 7?

I am deleting an item like this. The delete method is excuting well but I can't echo the last executed query.
public function deleteItems(Request $request){
$query=null;
switch($request->category){
case('categorylist'):
$category = category::find($request->id);
$query=$category->delete()->toSql();
break;
default:
}
echo json_encode(array('status'=>2, 'msg'=>'Successfully deleted', 'query'=>$query->toSql()));
}
The toSql() method works only on instances of Illuminate\Database\Query\Builder ( query builder as it is usually called ). Methods like where(), orderBy() etc return an instance of query builder, hence toSql() works on them. The delete() method does not return an instance of query builder ( I think it returns Boolean or the id it deleted. Can't remember ). So the toSql() method won't work.
If you just want to get the last executed query, then you could use DB::getQueryLog(). For example
DB::enableQueryLog();
$category->delete();
$queryLog = DB::getQueryLog();
// Now $queryLog will contain all the SQL queries which were executed after the DB::enableQueryLog()
$last = end($queryLog);
$query = $last['query'];
$bindings = $last['bindings'];

How to get item from laravel eloquent collection by conditions?

I use laravel eloquent to get files of post that give me a collection
but I want an item from that collection by condition.
For example from that collection I want an item that type = 'product'.
I am using foreach and check every item that have my condition and return it, but isn't any better way?
I tested collection method like contain but it return null.
Files item have type filed that value is 'product' or 'blog'.
My code:
$post= Post::where('slug' , $slug)->first();
$cover = $post->files->contains(['type' , '=' , 'product']);
Use the collection filter method.
$cover = $post->files->filter(function($file) {
// show only the items that match this condition
return collect(['product', 'blog'])->contains($file->type);
});
The filter method filters the collection using the given callback, keeping only those items that pass a given truth test:
$filtered = $post->files->filter(function ($value, $key) {
return $value->type == 'product';
});
$filtered->all();
Collections - filter()

Laravel Add Additional Rows to an Eloquent Object

I want to add an "On This Day" feature which should display records from The Previous Years. I have some Entries, all of them have a 'date' attribute. This is what I've been trying so far:
public function filterByDay($id){
$entries = Entry::where('id', $id)->get();
$currentDay = $entries[0]->date;
$oldestYear = Entry::orderBy('date','asc')->first()->date;
$previousYear = $currentDay;
while($previousYear >= $oldestYear ){
$previousYear = $currentDay->subYear();
$entries->push(Entry::where('date', $previousYear)->get());
}
return view('home')->with(compact('entries'));
}
I must send a Collection of "Entry" type from this controller method so that I can use $entry->title etc in the view. But whenever I'm using $entries->push(...) , I'm getting a Collection instance, not Entry instance. How can I convert the Collection back into Entry instance? Or what is the alternative? I'm using Laravel 5.5. Some help will be much appreciated.
You can combine whereDay, whereYear and whereMonth methods to achieve it in one liner:
$entries = Entry::where('id', $id)->get();
$today = Carbon\Carbon::now();
$oldestYear = Entry::orderBy('date','asc')->first()->date;
$allEntries = Entry::whereDay('date', $today->day)
->whereYear('date', '>=', $oldestYear)
->whereMonth('date', $today->month)
->get();
return view('home')->with(compact('allEntries'));

Pagination not working on multiple querying

I have a multiple query, but for some reason the pagination is not working, i dont no if the ussue is the way i construct it.
My code:
$query = \DB::table('products');
if ($request->has('type') && $type) {
$query->where('product_type_id', $type);
}
if ($request->has('material') && $material) {
$query->join("product_attribute_materials","products.id","=","product_attribute_materials.product_id")
->whereIn("product_attribute_materials.product_material_id", $material);
}
if($request->has('businessarea') && $area){
$query->join("product_attribute_businessareas","products.id","=","product_attribute_businessareas.product_id")
->whereIn("product_attribute_businessareas.product_businessarea_id", $area);
}
$products = $query->paginate(15);
You need to append the query string to the pagination using append() on $products
Passing array with the keys that you want to pass the query string, will return its value on the next request.
To confirm this, chick the href value from your browser before clicking on page number 2.
$products = $query->paginate(15)->appends(['type', 'material', 'businessarea']);

Resources