Conditional Join Eloquent - laravel

I have been looking through multiple question on stack overflow and also in the eloquent documents and I cannot seem to find how to join a table only if a variable is true.
I have my eloquent query.
$test = false;
$orderBy = 'name'; // Default order by
$sortBy = 'asc'; // Default sort by
$wheres[] = ['is_deleted', '=', $is_deleted];
Comm::where($wheres)
->select($selects)
->join('div', function($join) use($test) {
if($test) {
$join->on('Comm.div_id', '=', 'div.div_id')
}
}
->orderBy($orderBy, $sortBy)
->paginate($per_page, '*', 'page', $page);
Now I know you can join using the document join methods like
->join('div', 'comm.div_id', '=', 'div.div_id')
Is there anyway to accomplish the conditional add I am trying to do? This is for an api and I want the user to be able to specify if they want certain tables included in the returns results. I havent been able to find a post about this type of functionality. When I run my example code with the test if statement i get an error of:
Parse error: syntax error, unexpected '}'

So after a while of trial and error, I found you can use conditional clauses to help with joining tables.
$comm = Comm::select($selects)
->when($useJoins, function($query) use ($withs) {
return $query->with($withs);
})
->orderBy($orderBy, $sortBy)
->paginate($per_page, '*', 'page', $page);
I'm leaving this here for future reference since there is not a very large amount of data for this type of joining. I have also tried it with the eloquent join methods and those also work I just left it in an array for the with for display purposes.

Related

How can I get the laravel join method without using foreach command?

How can I get the laravel join method without using foreach command? How can I solve it without using the Foreach command
{{$app->name}} I used to this type. But I'm constantly getting error.
Controller.php file content
public function show($id)
{
$show = Duty::where('duty_id', '=', $id)->count();
if ($show!=0){
$app = DB::table('users')
->join('duties', 'duties.appointed_user_id', '=', 'users.id')
->select('users.name', 'duties.*')
->get();
$data = Duty::where('duty_id', '=', $id)->get();
return view('duty.show', compact('data', 'app'));
}
else
{
return redirect()->back()->with('status', 'Sorun oluştu');
}
}
Property [name] does not exist on this collection instance. (View: D:\xampp\htdocs\personality\resources\views\duty\show.blade.php)
You have a list (collection) of users, not a single user. That is why you can't get just the name from it, because it doesn't know which one to get the name of. This problem has nothing to do with using the join method.
If you only expect to get one result from your query, you could change from ->get() to ->first(). This would allow you to call {{$app->name}} without breaking. But only do this if you expect a single result and use first.
If you expect more than one user, there is no way to display the names without looping in some way.
That's what relationships are for. In that case you could do User::with(:duties'). Or in your case the other way around would probably work better Duty::find($id)->with('user')

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();

Why `having` only worked on fields that are `group by` on laravel eloquent?

My script laravel eloquent like this :
$query = $this->item->select('a.*','b.attribute_code')
->from('items as a')
->join('attr_maps as b','b.number','=','a.number')
->groupBy('a.number');
foreach($param as $key => $value) {
$query = $query->having($key, '=', $value);
}
$query = $query->paginate(10);
My $param is dynamic. It can change
If $param is array('number'=>'1234'), it works. No error
If $param is array('description'=>'test'), there exist error : Unknown column 'description' in 'having clause'
I tried all fields in the table items. Only the number field works. Apparently because the number field is group by
How can I make all field in the items table works if using having?
The HAVING clause is used in the SELECT statement to specify filter conditions for a group of rows or aggregates. The HAVING clause executed after SELECT, so if you apply HAVING on columns which is not in group by or not in aggregate function then it will work as where, which is no use because select clause is already executed. And i think just because of that eloquent may throw exception, not sure though.
What you can do, check your param key if it is in group by fields then apply having if not then add it as where condition like this.
$query = $this->item->select('a.*','b.attribute_code')
->from('items as a')
->join('attr_maps as b','b.number','=','a.number')
->groupBy('a.number');
foreach($param as $key => $value) {
if($key== 'number'){
$query = $query->having($key, '=', $value);
}else{
$query = $query->where($key, '=', $value);
}
}
you can check here WHERE vs HAVING
It's because Laravel's Eloquent ORM is active-record inspired and very database centric.
In the end, it's mainly because having is an sql concept which is used to filter rows in aggregate results.
In short, you're dealing with patches to problems in the SQL language which the Eloquent ORM has not abstracted away.

Using Laravel 5.4 query builder with an array (json serialized) attribute

I'm stumped on this one. I can search an array of ids but I want to search the reverse. I have models with lists of ids as "with_ids" attribute and want to search similar to mongo db where id is in that array of ids.
For example
db.conversations.find( { with_ids: { $in: [id] } } )
How do I do that with Laravel and mysql/Eloquent?
$conversations = Conversation::with('messages.user')->where('with_ids', $id)->orWhere('created_by', $id)->get();
it's the where('with_ids', $id) I can't figure out... Any suggestions??
To clarify further:
I need to find if the user is participating in other conversations as well as the ones he created. The with_ids is a json serialized array f.ex [1,2,23,12] how do i search inside the array attribute?
Not sure I understand. Did you try with whereIn();
$conversations = Conversation::with('messages.user')
->whereIn('with_ids', [$id])
->orWhere('created_by', $id)
->get();
Edit
$conversations = Conversation::with('messages.user', function($query) {
$query->where('id', $id); // user_id ?
})
->orWhere('created_by', $id)
->get();
After MUCH digging I finally found a solution. FIND_IN_SET in a whereRaw query did the trick. In case anyone else has come upon this issue, hope it helps.
it's not pretty because for some reason quotes need to be stripped out
Conversation::where('created_by', $id)->orWhereRaw("FIND_IN_SET(?, REPLACE(REPLACE(REPLACE(with_ids, '\"', ''), '[', ''), ']','')) > 0", $id)->get()
That's the final query to get aggregated conversations where user either created or is part of.

Laravel Eloquent ORM eager loading. Relation incorrectly returned as null

I have an Eloquent ORM relationship defined as follows:
ProductConfiguration:
public function product()
{
return $this->belongsTo('Excel\Products\Product');
}
public function currency()
{
return $this->belongsTo('Excel\Currencies\Currency');
}
Product
public function productConfigurations()
{
return $this->hasMany('Excel\Products\ProductConfiguration');
}
public function productType()
{
return $this->belongsTo('Excel\Products\ProductType');
}
I expect that if I do the following that I will load all product configurations of a specified product type, with the related products, nested product type details and the product configuration currency
$results = ProductConfiguration::with(
array(
'product' => function($query) use ($product_type) {
$query->where('product_type_id' , $product_type);
},
'product.productType',
'currency'
)
)
->get();
however the returned collection has 'product' set to NULL. the Currency Relationship is there, but the product relationship is not. I can see the outputted SQL queries and the query that selects the products retrieves the correct products if I paste it directly into my sql editor
select * from `products`
where `products`.`id` in ('12', '13')
and `product_type_id` = '1'
Am I correct to think that the results from this query should be included in my collection, or is there some obvious flaw in my thinking?
I think you don't want to achieve that. Now what you get is getting all ProductConfiguration with products that are only of certain_type.
So in case you have some configuration that has other type for product you will get null because you limited results from product to only the one that has certain product type.
I might be wrong, but you probably wanted to get those ProductConfiguration that belongs to Product that is type of certain_type. In this case you should use whereHas:
$results = ProductConfiguration::
with('product', 'product.productType', 'currency')->
whereHas('product', function($q) use ($product_type)
{
$q->where('product_type_id', '=', $product_type);
})->get();
I hate to post this as an answer but since i don't have enough rep to comment so try this first:
$results = ProductConfiguration::with('product')->get();
dd($results->toArray());
See what you get, if you get some data, try this
$results = ProductConfiguartion::with(array('products' => function($query){
$query->where('product_type_id' , $product_type);
})->get();
dd($results);
See what you get, if you get null: your $product_type variable may be something you didnt expect, so try dd($product_type) to make sure its what your expecting.

Resources