Laravel whereBetween with optional parameter - laravel

I need to construct query using whereBetween clause, but with a twist for which i didn't find a answer applicable in my case. I need, for when from parameter isn't present to regard that as to query from beginning. If to parameter isn't present, then needs to look everything after previously mentioned parameter.
Query currently:
Vehicle::whereBetween("updated_at", [$dates->start_date, $dates->end_date])->with("something")->get();
How i wanted it to be:
Vehicle::whereBetween("updated_at", "lookup from start date if present, if not, look from beginning", "lookup to said end date if it's present, if not, look up till the end"])->with("something")->get();
I am asking, what is appropriate to put in, when parameter isn't present so it works in way i described?
Edit:
If omitted, start date, query works fine. If end date gets omitted, query return zero in best case scenario. Worst case, throws an error.
I tried putting null, empty string, false, zero(0), for end date, nothing works.

It would make more sense to not use whereBetween and simply add where clauses conditionally. You could do this with the when() method:
Vehicle::with("something")
->when($dates->start_date, function ($query, $date) {
$query->where('updated_at', '>=', $date);
})
->when($dates->end_date, function ($query, $date) {
$query->where('updated_at', '<=', $date);
})
->get();

Related

Method Illuminate\Database\Eloquent\Collection::orderby does not exist

$posts = Post::all()->orderby('created_at','desc')->where('usr_id','=',session('LoggedUser'))->get();
return view('admin.profile',compact('userInfo' , 'posts'));
i am making a custom auth for a journal activity but i cant sort the content i shows this error
"Method Illuminate\Database\Eloquent\Collection::orderby does not exist. "
$posts = Post::where('usr_id','=',session('LoggedUser'))->orderby('created_at','desc')->get();
True query like that. When you take all() already query done.
Change it to:
$posts = Post::where('usr_id','=',session('LoggedUser'))->orderby('created_at','desc')->get();
you cant use all() and orderBy because all() does not allow the modification of the query.
I believe this might be because you typed orderby instead of orderBy (notice the uppercase). See laravel orderBy documentation if needed.
Plus, as mentionned by other, don't use all() if you need to do other thing (where clause, order by, etc) in you query.
Change the orderby to orderBy. This could be the reason you are getting the error.
$posts = Post::all()->orderBy('created_at', 'DESC')->where('usr_id','=',session('LoggedUser'))->get();
return view('admin.profile',compact('userInfo' , 'posts'));
Or...
If you want to get specific number of posts you can do it this way to avoid using the Post::all
$posts = Post::orderBy('created_at', 'DESC')->where('usr_id','=',session('LoggedUser'))->paginate(5);
return view('admin.profile',compact('userInfo' , 'posts'));
Yeah this is pretty confusing and just got me as well.
The actual problem isn't the capitilization typo (orderby versus orderBy) but rather the fact that you're using ->all() instead of just Model::orderBy()->...
The moment you use ->all() the object is transformed to another type of collection object and the normal methods one would expect do not exist.
In this case you should rather use sortBy().
See here.

Is there a way to select one url among multiple picture urls with "exists" condition in laravel?

I have several picture urls some of them may exists in the table, some of them may not. Columns are "picture, picture_thubnail, company_logo_thumbnail, company_logo". I want to select picture thumbnail as lets say "picture_url". But if "picture_thumbnail" does not exists, I want to pick "picture" as "picture_url". If "picture" does not exists I want to pick company_logo_thumbnail and so on... as a result I will get a picture_url as a string or null.
edit: this should be done in a single query instead of multiple queries with if else. or more elegant solutions are appretiated.
Sounds more like a database thing than a Laravel thing (the easiest way I can think of anyway).
$images = DB::table('images')
->select(DB::raw('COALESCE(picture_thumbnail, picture, company_logo_thumbnail, company_logo) as picture_url'))
->get();
The MySQL COALESCE function returns the first non-null result.
This is also assuming that you are using MySQL as your database engine.
UPDATE
To check a column in another table you could use a join.
$images = DB::table('images')
->select(DB::raw('COALESCE(picture_thumbnail, picture, company_logo_thumbnail, company_logo, company_logos.id) as picture_url'))
->leftJoin('company_logos', 'company_logos.id', '=', 'images.company_logo_id')
->get();
I've used company_logos.id in the select, but guessing it would be something like company_logos.picture or something with the filename, rather than the id of the row.
UPDATE 2
I would change this to be a left join:
->join('cloudfiles', function ($join) {
$join->on('userdetails.company_logo_id', '=', 'cloudfiles.id')->where('company_logo_id', '!=', null);
})
->leftJoin('cloudfiles', function ($join) {
$join->on('userdetails.company_logo_id', '=', 'cloudfiles.id')->where('company_logo_id', '!=', null);
})
A left join would mean you still get all results from the userdetails where as a normal join would mean only userdetails that have an associated cloudfiles record would be returned.
Secondly, I'd change this:
->where('company_logo_id', '!=', null)
to
->whereNotNull('company_logo_id')
Although I think you might be able to remove that condition completely.
Couple of other points, just fyi:
$boothOwner = Booth::where('id', '=', Request()->booth_id)->firstOrFail();
could be (unless there are somehow duplicate ids in the table)
$boothOwner = Booth::findOrFail(Request()->booth_id);
Similarly,
->whereRaw('userdetails.user_id = ?', [$boothOwner->user_id])
could be
->where('userdetails.user_id', $boothOwner->user_id)

Manual function inside query?

Is there any way to put a manual function inside a query in Laravel.
I've timestamp saved in string in DB. I want to convert timestamp from one timezone to another. All the timestamp is inserted in one time zone, and depending upon my user I fetch the timestamp and convert it into their timezone.
what I want to achieve is something like this..
$query = BlogCategory::select('merchant_id', userTime(added_at))
->where('site_id', $site_id)
->get();
userTime() function takes two parameter, the timestamp and the timezone and converts the timsestamp to time of the user.
I want to use userTime() function before fetching the data. I dont want to fetch the data first and then do foreach and so on.
I know I might be absolutely absurd but is there anything of this sort in Laravel?
Well you can achieved that using collection map
$query = BlogCategory::select('merchant_id', 'added_at')
->where('site_id', $site_id)
->get();
$dateAdded = $query->map(function ($data) {
// try this if error $data['merchant_id']
return array(
'merchant_id' => $data->merchant_id,
'added_at' => $this->userTime($data->added_at)
);
})
dd($dateAdded);
Read Collection documentation here: https://laravel.com/docs/5.8/collections
You should use the selectRaw statement and let your DB do this logic for you if you don't want to loop over the result set.
For example if your underlying database is MySQL you can use the CONVERT_TIMEZONE function and do something like this.
BlogCategory::selectRaw('merchant_id, CONVERT_TZ(added_at, "GMT", "MET") as added_at')
->where('site_id', $site_id)
->get();

Laravel 5.7 eloquent query with multiple wheres and a whereNotIn

I'm attempting to execute a query that gets a data set based on a user id matching two possible columns and a workflow_state not matching two values. My attempt is here:
$usersBugs = Bug::where('assigned_user_id', $user->id)
->orWhere('reported_by', $user->id)
->whereNotIn('workflow_state', ['closed', 'rejected'])
->get();
It is returning a "bug" with a rejected workflow_state. I'm guessing it is executing the whereNotIn as an or? How would I refactor this to execute that the bug cannot be in either of those two states (no matter what) and it can match either the assigned_user_id OR the report_by. I tried leading with the whereNotIn:
$usersBugs = Bug::whereNotIn('workflow_state', ['closed', 'rejected'])
->where('assigned_user_id', $user->id)
->orWhere('reported_by', $user->id)
->get();
Either way it is returning a matched bug based on the assigned_user_id, despite the fact that the workflow_state is rejected.
You may try this:
$model->whereNotIn(...)->where(function($query) use ($user) {
$query->where('assigned_user_id', $user->id)->orWhere('reported_by', $user->id);
})->get();
You should wrap where .. orWhere into additional closure:
$usersBugs = Bug::where(function($q) {
$q->where('assigned_user_id', $user->id)
->orWhere('reported_by', $user->id)
})->whereNotIn('workflow_state', ['closed', 'rejected'])->get();

Eloquent ORM, how to avoid redundant queries?

Suppose I have the field status in all my database tables. When I want to delete a record, instead of purging it I set the value of field status to 0. This means of course all my queries will always use a where clause such as:
WHERE status = 1
However, this means I have to write and append where('status', '=', 1) to all methods of my eloquent model. It will always be like:
Post::find(1).where('status', '=', 1)
Post::where('status', '=', 1)->get()
Post::find(1).where('status', '=', 1).comments().where('status', '=', 1)->get()
Is there a way to define something as a default scope to have where status = 1 always present in all methods of my model and all the time?
I appreciate any help!
This should do the trick, at least regarding soft delete:
http://four.laravel.com/docs/eloquent#soft-deleting
You could use the scope methods.
public function scopeActive($query)
{
$query->where('status', '=', 1);
}
Then, you use like this:
Post::active()->get();

Resources