Laravel orm with() not works - laravel

JoinSkipReason has not id, but JoinReview's primary key is foreign key of JoinSkipReason.
Query Builder works well...
I want to use with() to join the JoinSkipReason to the JoinReview table.
Thank you.
JoinReview::with(
'join_skip_reason'
);
class JoinReview extends Model
{
public function joinSkipReason()
{
return $this->hasOne('App\Models\Service\JoinSkipReason');
}
}
class JoinSkipReason extends Model
{
protected $fillable = ['join_review_id', 'reason'];
public function joinReview()
{
return $this->belongsTo('App\Models\Service\JoinReview', 'id');
}
}

I've encountered this issue myself, the issue is that for eager loading multi-word relations you should use camelCase.
In your code:
JoinReview::with(
'joinSkipReason'
);
I've also found a (kinda old) issue saying that you should also access the eager-loaded relation as camelCase, otherwise it will ignore the cached result and query the database again.

Check do like that
public function joinSkipReason()
{
return $this->hasOne('App\Models\Service\JoinSkipReason','join_review_id','id');
}

Related

Laravel many-to-many relation required unexpected table name

I have two tables with many-to-many relation
class Psychologist extends Model
{
public function specs()
{
return $this->belongsToMany('App\Models\Spec');
}
public function methods()
{
return $this->belongsToMany('App\Models\Method');
}
}
Its working fine on saving first relation 'App\Models\Spec' $psy->specs()->attach(explode(',',$data['spec'])); with table name 'psychologist_spec' and get exception of incorrect table 'method_psychologist'
instead of 'psychologist_method'
public function save(Request $req)
{
$data = $req->all();
$psy = Psychologist::create($data);
$psy->specs()->attach(explode(',',$data['spec']));
$psy->methods()->attach(explode(',',$data['methods']));
}
I know that i can explicitly indicate table name like
public function methods()
{
return $this->belongsToMany('App\Models\Method', 'psychologist_method');
}
but cant understand why it working in the first case and doesnt in the second
Eloquent will join the two related model names in alphabetical order

Laravel 5: Eloquent relationship method with conditions

Normal relationship methods don't usually have a condition, and tend to look like this:
class StripeCustomer extends Model
{
public function user()
{
return $this->belongsTo(User::class, 'stripe_customer_id');
}
}
In my model I have a condition in the relationship method like so:
class StripeCustomer extends Model
{
public function user()
{
if ($this->type === 'normal') {
return $this->hasOne(User::class, 'stripe_customer_id');
} else {
return $this->hasOne(User::class, 'stripe_customer_charity_id');
}
}
}
Does Laravel support conditional relationships in Eloquent like above. A lot of the usual methods still work like so:
StripeCustomer::get()->first()->user;
StripeCustomer::get()->first()->user()->get();
But would the following work predictably:
Foo::with('user')->get();
The issue here is that I am unsure in how the "with" operator works in Eloquent internally.
A reason I believe it also doesn't work is that the user() method needs to be executed for every model. However, when I added a dump(...) at the start of the method, I found it was only run once, indicating that with() does not work.
No, it won't work with with(). What do you think will happen when you try to execute the following code:
Foo::with('user')->get();
The answer is Laravel will create new instance of Foo and try to call user() to get the relationship object. This new instance doesn't have any type ((new Foo)->type will be null), therefore your method user() will always return $this->hasOne(Bar::class, 'b_id') and this relationship object will be used to construct a query.
As you can see this is clearly not what you wanted since only type B users will be eager loaded for all Foo rows. What you need to do in this case is create two relationships (one for each type) and accessors (get/set) for user:
class Foo extends Model
{
public function userA()
{
return $this->hasOne(Bar::class, 'a_id');
}
public function userB()
{
return $this->hasOne(Bar::class, 'b_id');
}
public function getUserAttribute()
{
if ($this->type === 'a') {
return $this->userA;
} else {
return $this->userB;
}
}
public function setUserAttribute($user)
{
if ($this->type === 'a') {
$this->userA()->associate($user);
} else {
$this->userB()->associate($user);
}
}
}
Then you can use with() for both relations to utilize eager loading:
$fooRows = Foo::with('userA', 'userB')->get();
...
foreach ($fooRows as $row) {
$row->user;
}
edit:
Since you've edited code in your question the example code in my answer no longer represents your case, but I hope you get the overall idea.
Yep, with() works. It runs a subquery on any relation your user() method returns. Since your relation already has a constraint, it applies said constraint to the subquery as you'd expect.

Laravel query multiple tables using eloquent

hi sorry bit of a newbie here but I am have three tables users, profiles, friends. they all have the user_id fields within them and I want fetch all of the fields in one statement using Eloquent and not DB::statement and doing the table joins.
How can I achieve this?
Try this
use the User class and the with method that laravel has to query model relationships
$user = User::with(['profile', 'friend'])->get();
Ensure your models has the correct relationships as follows:
app/models/User.php
public function friend () {
return $this->hasMany('Friend');
}
public function profile () {
return $this->hasOne('Profile');
}
app/models/Profile.php
public function user() {
return $this->belongsTo('User');
}
app/models/Friend.php
public function user() {
return $this->belongsTo('User');
}
use some thing like this:
You should define relations in your models with hasOne, hasMany.
class Review extends Eloquent {
public function relatedGallery()
{
$this->hasOne('Gallery', 'foreign_id', 'local_id');
}
}
class Gallery extends Eloquent {
public function relatedReviews()
{
$this->hasMany('Review', 'foreign_id', 'local_id');
}
}
$gallery = Gallery::with('relatedReviews')->find($id);
Will bring the object Gallery with
$gallery->id
gallery->name
...
$gallery->relatedReviews // array containing the related Review Objects

In Laravel, how to set up a relationship for a "likes" table? Also, how to include that information in a query?

I have three tables: users, ideas, and ideas_likes. The ideas_likes table looks like:
ideas_likes
------------
id primary key
user_id foreign key
idea_id foreign key
liked boolean
There's already a one-to-many relationship set up between users and ideas. It looks something like this:
class User extends Ardent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
protected $table = 'users';
public function ideas()
{
return $this->hasMany('Idea');
}
}
Similarly, the idea model looks like this:
class Idea extends Ardent {
protected $table = 'ideas';
public function user()
{
return $this->belongsTo('User');
}
}
My first question is: How do I create the IdeaLike model? And once that is finished, using Eloquent, how do I retrieve all liked ideas for a user?
===========================================================================
Lucasgeiter's updated solution worked great.
First, there's no need to create an IdeaLike model. You just need a many-to-many relationship
User
public function ideas(){
return $this->belongsToMany('Idea', 'ideas_likes')->withPivot('liked');
}
Idea
public function users(){
return $this->belongsToMany('User', 'ideas_likes')->withPivot('liked');
}
(By adding withPivot I tell Laravel that I want to have the liked column from the pivot table included in the result)
Usage
$user = User::find(1);
$likedIdeas = $user->ideas()->where('liked', true)->get();
By the way: You don't need to specify the $table if it is the plural of the model name.
Update
It looks like you actually really do need both, a one-to-many and a many-to-many relation.
So your final relations would look like this:
User
public function ideas(){
return $this->hasMany('Idea');
}
public function liked(){
return $this->belongsToMany('Idea', 'ideas_likes')->withPivot('liked');
}
Idea
public function likes(){
return $this->belongsToMany('User', 'ideas_likes')->withPivot('liked');
}
public function user(){
return $this->belongsTo('User');
}
(I just chose names for the relations that made kind of sense to me. You can obviously change them)
Usage
Liked ideas by a certain user: (id = 1)
$ideas = Idea::where('user_id', 1)->whereHas('likes', function($q){
$q->where('liked', true);
})->get();

Issue with Laravel hasMany relation

I’m having an issue with relations in two of my models in a Laravel application. My models are:
class Invoice extends Eloquent {
protected $table = 'invoices';
public function line_items()
{
return $this->hasMany('LineItem');
}
}
And:
class LineItem extends Eloquent {
protected $table = 'line_items';
public function invoice()
{
return $this->belongsTo('Invoice');
}
}
In my controller, I fetch an Invoice row with the following:
$invoice = Invoice::find($id);
However, if I try and access the line_items property to fetch the LineItem rows relating to my invoice, I get the following error:
Invalid argument supplied for foreach()
Why is this? I’ve set my models up as per Laravel’s documentation: http://laravel.com/docs/eloquent#one-to-many
change
public function line_items()
for
public function lineItems()
and it will work , tested in Laravel 4.1 :)
Check your tables relations... (Schema)
Your FK must be lineitem_id... You have modified this? Laravel will configure automatically... Don't change this...
Then, try
$invoice->line_items() or $invoice->line_items in 4.1
Check for line_items before the foreach loop:
if(! $invoice->line_items->isEmpty()){
foreach($invoice->line_items as $line_item){
//do stuff
}
}
Also, it won't hurt to explicitly mention the FK, although laravel will automatically try to do it for you provided you use proper names for your table fields.
//Invoice Model
return $this->hasMany('LineItem', 'invoice_id');
//LineItem Model
return $this->belongsTo('Invoice', 'invoice_id');

Resources