Reputation: 11
I want to use WhereIn in my model, but its always returning null audience_id, i also wanted to take Audience detail from audience_id that i got in events table. thats why i used WhereIn
`<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
/** @use HasFactory<\Database\Factories\EventFactory> */
use HasFactory;
protected $guarded =[];
protected $casts = [
'audience_id' => 'json',
'location' => 'json',
'guest_type' => 'json',
];
public function audiences()
{
dd($this->audience_id);
$audienceId = $this->audience_id['id'] ?? null;
if ($audienceId) {
return $this->hasMany(Audience::class, 'id')->whereIn('id', $audienceId);
}
return $this->hasMany(Audience::class, 'id')->whereIn('id', []);
}
}`
whenever i use dd, its always returning null. And here is my table :
`public function up(): void
{
Schema::create('events', function (Blueprint $table) {
$table->id();
$table->string('category');
$table->string('title');
$table->json('location');
$table->json('audience_id');
$table->json('guest_type');
$table->integer('time_span');
$table->string('type');
$table->timestamps();
});
}
`
Upvotes: 1
Views: 57
Reputation: 86
It seems like the relationship logic is a bit over-complicated here.
When you're defining a relationship, the method is called before the data is actually retrieved, which is why you're getting null.
// This gives null because data isn't loaded yet
Event::with('audiences')->first();
// This gives the value of audience_id in the first row
Event::first()->audiences;
This works because the data is retrieved before audiences function is called.
Now for the solutions part, It looks like you're trying to create a relationship between Event and Audience. The correct database structure would have the event_id in the audiences table. You can then define the relationship like this:
In Event Model
public function audiences()
{
return $this->hasMany(Audience::class, 'event_id', 'id');
}
and In Audience Model:
public function event()
{
return $this->hasOne(Event::class, 'event_id', 'id');
}
If you can't make changes to the database, an alternative approach would be to use a package like https://github.com/staudenmeir/eloquent-json-relations. While I haven't personally used it, it looks like it could solve the issue you're facing.
There is also a same kind of a question which you are refer: Laravel hasMany on json field
Upvotes: 1
Reputation: 989
While I do not know why $this->audience_id
is empty I am fairly certain this is not how Eloquent relationships are supposed to be used.
If Event-Audience is a one-to-many relationship then I would expect an event_id in the audiences table. If it were a many-to-many I would use a pivot table 'audience_event'.
If you insist on your datamodel you could remove the relation in the Event model, and instead manually add the related items using setRelation()
, like this:
// Retrieve an event.
$event = Event::first();
// Get the array of ids, expected contents are something like {"id": [1, 2, 3]}.
$audienceIds = $event->audience_id['id'] ?? null;
// Retrieve audiences.
$audiences = Audience::whereIn('id', $audienceIds)->get();
// Add to the event.
$event->setRelation('audiences', $audiences);
Then a dd($event);
would show this, as if there were an actual relationship defined in the model.
App\Models\Event {#1337 ▼ // app\Http\Controllers\MyController.php:23
<snip>
#relations: array:1 [▼
"audiences" => Illuminate\Database\Eloquent\Collection {#1345 ▼
#items: array:3 [▼
0 => App\Models\Audience {#1347 ▶}
1 => App\Models\Audience {#1360 ▶}
2 => App\Models\Audience {#1359 ▶}
]
#escapeWhenCastingToString: false
}
]
<snip>
}
I am not an expert in Eloquent. Maybe there is a way to implement a relationship that looks more like your code, but this is an easy altenative.
Upvotes: 0