use of orWhere() in Eloquent - laravel

I have a eloquent query that I am running twice, but feel can be run once.
I'd want to return the values of the first where statement if exists otherwise check the second where statement which is the default in the query.
This is what I am currently doing:
$details = Telco::select('telcos.id AS telco_id', 'telcos.name AS telco_name')
->leftJoin('telco_prefixs', 'telco_prefixs.telco_id', '=', 'telcos.id')
->where('telco_prefixs.prefix', '=', $phone_number) // check if ndc exists
->first();
if ($details){
return $details;
}
return Telco::select('telcos.id AS telco_id', 'telcos.name AS telco_name')
->leftJoin('telco_prefixs', 'telco_prefixs.telco_id', '=', 'telcos.id')
->where('telcos.name', '=', 'Default') //default channel
->first();
I have a feeling this can be combined to something like below:
However, this fails as keeps executing the OrWhere clause.
Telco::select('telcos.id AS telco_id', 'telcos.name AS telco_name')
->leftJoin('telco_prefixs', 'telco_prefixs.telco_id', '=', 'telcos.id')
->where('telco_prefixs.prefix', '=', $phone_number) // if ndc exists
->Orwhere('telcos.name', '=', 'Default') //default channel
->first();
Someone help. Thanks

Try to add your where and or where condition as below.
Telco::select('telcos.id AS telco_id', 'telcos.name AS telco_name')
->leftJoin('telco_prefixs', 'telco_prefixs.telco_id', '=', 'telcos.id')
->where(function ($query) use($phone_number) {
$query->where('telco_prefixs.prefix', '=', $phone_number);
$query->Orwhere('telcos.name', '=', 'Default');
})->first();

I you want to use just eloquent a possible solution would be to have something like:
I suppose you have model called Telco and another one calle TelcoPrefix.
//Telco.php
//first we create a has many relationship with your telco_prefixs table.
public function telcoPrefixs(){
return $this->hasMany(TelcoPrefix::class);
}
Once you have that relationship you can use something similar to this code:
Telco::whereHas('telcoPrefixs',function($query, $phone_number){
return $query->where('prefix,'=',$phone_number);
})->select('id','name')->first();
This will compare the relationship and if it exists or has it will return your first record in one query.
Hope it helps at least to give a guide of what you can do.

Related

how to use whereHas in laravel

I am new to laravel,
I need to create a query for the db,
$query = Deal::query();
I want to use the wherehas operator.
this is my code that is worked.
else if ($group_by == 'precedence') {
if($get_deals_for == 'noprecedence'){
$get_deals_for = 0;
}
$precedenceStatus = $get_deals_for;
$query-> where('precedence', '=', $precedenceStatus);
// \Log::info('The request precedence: '.$precedenceStatus);
}
I want to add this code also to the query
if($person) {
$query->whereHas('personnel', function ($subQuery) use ($person) {
$subQuery->where('id', '=', $person);
});
}
So I need to change the first code?
how I can convert the first code to wherehas?
the first code is from table called deal, the second section is from realtionship called personnel.
the second section worked in other places in the code, I just need to fix the first section and not understand what to write in the use
I try this and get error on the last }
else if ($group_by == 'precedence') {
if($get_deals_for == 'noprecedence'){
$get_deals_for = 0;
}
$precedenceStatus = $get_deals_for;
$query-> where('precedence', '=', $precedenceStatus)
-> when ($person, function($query) use($person) {
$query->whereHas('personnel', function ($query) use ($person) {
$query->where('id', '=', $person);
});
})
}
There is a method you can use called when(, so that you can have cleaner code. The first parameter if true will execute your conditional statement.
https://laravel.com/docs/9.x/queries#conditional-clauses
$result = $query
->where('precedence', '=', $precedenceStatus)
->when($person, function ($query) use ($person) {
$query->whereHas('personnel', fn ($q) => $q->where('id', '=', $person));
})
->get();
You should also be able to clean up your precedence code prior to that using when( to make the entire thing a bit cleaner.
Querying to DB is so easy in laravel you just need to what you want what query you want execute after that you just have to replace it with laravel helpers.Or you can write the raw query if you cant understand which function to use.
using,DB::raw('write your sql query').
Now Most of the time whereHad is used to filter the data of the particular model.
Prefer this link,[Laravel official doc for queries][1] like if you have 1 to m relation ship so u can retrive many object from one part or one part from many object.like i want to filter many comments done by a user,then i will right like this.
$comments = Comment::whereHas('user', function (Builder $query) {
$query->where('content', 'like', 'title%');
})->get();
$comments = Here will be the model which you want to retrive::whereHas('relationship name', function (Builder $query) {
$query->where('content', 'like', 'title%');
})->get();
you can also write whereHas inside whereHas.
[1]: https://laravel.com/docs/9.x/eloquent-relationships#querying-relationship-existence

Laravel: Use order by in combination with whereHas

I want to retrieve a collection of data, which is ordered by the start_date of the relation
Basically I want to achieve this, with Laravel Models (the code below works perfectly)
$posts = DB::table('posts')
->leftJoin(
'threads',
'posts.id',
'=',
'threads.postable_id'
)
->where('threads.postable_type', '=', 'App\Post')
->orderBy('threads.start_date')
->paginate($request->input('limit', 2));
So in this case, I'm fetching ALL Posts and those are ordered by the start_date of the thread relation.
Those are not my actual tables but this works perfectly!
Because I'm using https://laravel.com/docs/8.x/eloquent-resources this is not the ideal solution to retrieve sorted data.
So instead I want to use the orderBy clause somewhere here
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now());
});
But I just cannot make this work. I've tried this
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now())
->orderBy('start_date');
});
and I also appended this to the actual relation:
public function thread(): MorphOne
{
return $this->morphOne('App\Thread', 'postable')->orderBy('start_date');
}
If you look at your code:
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now())
->orderBy('start_date');
});
the whereHas will only return Post associate with a thread which the function return true.
Try this:
$posts = Post::with('thread')->has('thread')->orderBy('thread.start_date')->get();
This will fetch all Post with Thread only if they have at least one Thread and then orderBy the start_date of the Thread.
You don't have to do the whereHas function because when you call ->with('thread') it'll use you this :
public function thread(): MorphOne
{
return $this->morphOne('App\Thread', 'postable')->orderBy('start_date');
}
whereHas doesnt retrieve the relationship.
If you need even more power, you may use the whereHas and orWhereHas methods to define additional query constraints on your has queries, such as inspecting the content of a comment: Laravel whereHas
Don't do :
$posts = Post::with('thread')->orderBy('thread.start_date');
If there is no thread on some post, post without thread will be fetch with value null for their key thread and you will have an unexpected result when you try to orderBy.
First of all I want to thank Elie Morin for his help but I found out that I definitely need to use joins for that task.
In my example, I wanted to order the main query (posts) by the relation's start_date
Doing what you suggested
$posts = Post::with('thread')->has('thread')->orderBy('thread.start_date')->get();
Would only order the thread by start_date and not the ENTIRE query.
Which is why I came up with something like this:
$posts = Post::has('thread')
->select('posts.id')
->leftJoin(
'thread',
'posts.id',
'=',
'thread.postable_id'
)
->where('thread.postable_type', '=', 'App\Post')
->where('thread.end_date', '>=', Carbon::now())
->orderBy('thread.start_date')
->with('thread');
return PostResource::collection($posts->paginate(2));

Laravel Query Builder result using join() query

The following query works fine, but the problem is that it gives the id of the events table instead of tasks table id in the output result.
Task::join('events', function ($join) {
$join->on('events.task_id', '=', 'tasks.id')
->where('events.event_type', '=', 'Task')
->where('events.task_stage', '!=', 'assigned');
})->select('tasks.*')
->get();
Try this, one should work
->select('*', 'tasks.id as taskID')->get();
This is because maybe both tasks and events table have id field. So u need to use a separate query to specify the id.
try this one
use mysql alias here
Task::join('events', function ($join) {
$join->on('events.task_id', '=', 'tasks.id')
->where('events.event_type', '=', 'Task')
->where('events.task_stage', '!=', 'assigned');
})->select('tasks.*','tasks.id as taskId')->get();

Join Laravel tables

I have got three tables Kudos, Kudoscategories, and specialpost. I need to get the data from those tables and check the post id using a where condition.
I have attached the database table screenshot here
I already tried this, but it's not getting any result.
$results = DB::table('kudos')
->select('kudos.description','kudoscategory.catname','kudoscategory.image','kudos.spid')
->join('kudoscategory', 'kudoscategory.id', '=', 'kudos.categoryid')
->where('kudos.spid', '=', $post_id)
->first();
return $results;
What I need to do is get the results using below where condition newsfeed_special_posts.main_post_id = kudos.spid
You must add another join with newsfeed_special_posts.
The query will be like,
$results = DB::table('kudos')
->select('kudos.description','kudoscategory.catname','kudoscategory.image','kudos.spid')
->join('kudoscategory', 'kudoscategory.id', '=', 'kudos.categoryid')
->join('newsfeed_special_posts', 'newsfeed_special_posts.main_post_id', '=', 'kudos.spid')
->where('kudos.spid', '=', $post_id)
->first();
return $results;
Though this is not a good practice for laravel. using laravel eloquent relationships will be more efficient for these results.
https://laravel.com/docs/5.8/eloquent-relationships
you can still do it this way. still efficient to avoid sql injection since you are getting all the record from the 3 tables. seeing your table above, its not properly normalised. anywaye try this.
$results = DB::table('kudos')
->leftjoin('kudoscategory', 'kudoscategory.id', '=', 'kudos.categoryid')
->leftjoin('newsfeed_special_posts', 'newsfeed_special_posts.id', '=', 'kudos.spid')
->where('kudos.spid', '=', $post_id)
->first();
return $results;
you can try this code
at first, create model Kudos,KudosCategory,NewsfeedSpecialPosts
Kudos Model
public function kudoscategory_dta()
{
return $this->belongsTo('App\Model\KudosCategory','categoryid');
}
public function newsfeed_special_posts_dta()
{
return $this->belongsTo('App\Model\NewsfeedSpecialPosts','spid','main_post_id ');
}
controller
Kudos::with('kudoscategory_dta','newsfeed_special_posts_dta')->first();

Eloquent ORM find by id and add where clause to a relationship model

Hey guys how you doing?
I'm trying to simply find by id and at the same time guarantee that a column from a relationship table is with a value.
I tried a few things but nothing works.
$tag = Tag::find($id)->whereHas('posts', function($q){
$q->where('status','=', 1);
})->get();
Also:
$tag = Tag::whereHas('posts', function($q) {
$q->where('status','=', 1);
})->where('id','=', $id)->get();
Can you help me?
It is a simple thing but I can't manage to do it...
You need to read on Eloquent docs. Learn what's find, first, get for that matter.
Your code does what you need, and more (a bit wrong though) ;)
$tag = Tag::find($id) // here you fetched the Tag with $id
->whereHas('posts', function($q){ // now you start building another query
$q->where('status','=', 1);
})->get(); // here you fetch collection of Tag models that have related posts.status=1
So, this is what you want:
$tag = Tag::whereHas('posts', function($q){
$q->where('status','=', 1);
})->find($id);
It will return Tag model or null if there is no row matching that where clause OR given $id.
Have you checked Query Scope ?
You can do this:
$tag = Tag::where('status', '=', 1)
->where('id', '=', 1, $id)
->get();

Resources