Hello I've got a problem with retrieving data from polymorphic relation in my Laravel 11 application. I am trying to retrieve all reports which are associated with one single Post.
It works with db facade like this
$reports = DB::table('reports')
->where('reportable_id', $this->post->id)
->where('reportable_type', 'Post')
->get();
And it gave me 2 reports which are associeted with one current post and that's correct according to database.
But with relations it doesn't retrieve anything.
This is relation in Report model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphMany;
class Report extends Model
{
public $guarded = ['id'];
public function reportable(): MorphTo
{
return $this->morphTo();
}
And this is my Post model
<?php
namespace App\Models;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Post extends Model
{
use HasFactory;
public $guarded = ['id'];
protected $casts = [
'archived_at' => 'datetime',
];
public function reports(): MorphMany
{
return $this->morphMany(Report::class, 'reportable');
}
and this is how I'm using relation for retrieving data, it shows me empty collection.
$post = $this->post->reports;
this is reports migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('reports', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id')->nullable();
$table->unsignedBigInteger('reportable_id')->nullable();
$table->string('reportable_type')->nullable();
$table->text('description')->nullable();
$table->boolean('spam')->nullable()->default(null);
$table->boolean('victimize')->nullable()->default(null);
$table->boolean('offensive')->nullable()->default(null);
$table->boolean('solved')->default(false);
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('reports');
}
};
this is post migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')
->constrained('users')
->cascadeOnDelete();
$table->foreignId('post_category_id')
->constrained('post_categories')
->cascadeOnDelete();
$table->string('title');
$table->text('body');
$table->date('archived_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};
Just let you know, that I've got same logic by Likes and Comments and it works perfectly and I'm able to retrieve data through relation. But by reports I'm not. :/ Maybe is here something what I don't see.
Code you shared is ok. It seems that problem is when you create reports: "reportable_type" should be Fully Qualified Class Name or, in this case "App\Models\Post" not just Post like in your DB example.
So, this should not work:
DB::table('reports')
->where('reportable_type', 'Post')
...
Reports Should be done like this:
$post->reports()->create([
'user_id' => $user->id,
'reason' => 'Offensive',
]);
or like this:
Report::create([
'user_id' => $user->id,
'reportable_id' => $post->id,
'reportable_type' => Post::class,
'reason' => 'Spam',
]);