Kolejna relacja polimorficzna, którą musimy przećwiczyć, czyli wiele do wielu. Zaczynajmy!
Ok, najpierw model Comment, z flagą -mfs. Tworzymy migrację:
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('title');
$table->text('content');
$table->morphs('commentable');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('comments');
}
};
Migracja podobna do poprzedniej, tu się nic nie zmienia. Teraz migrujemy i model Comment:
class Comment extends Model
{
use HasFactory;
protected $fillable = ['title', 'content'];
public function commentable()
{
return $this->morphTo();
}
}
Też morphTo, odpowiednik belongsTo. Ok, teraz Review i Movie (w następnych lekcjach pokażę, jak to usprawnić), dodajemy tam (pamiętając o importach) taką metodę:
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
Ok, komenda comment-for-movie:
Artisan::command('comment-for-movie {id}', function (int $id) {
$m = Movie::findOrFail($id);
$c = new Comment();
$c->title = "Comment for Movie {$id}";
$c->content = "Content about movie {$id}";
$m->comments()->save($c);
$this->comment("done");
});
Używamy i patrzymy na bazę danych plus ja mam nadzieję, że ogarniamy, że możemy też używać createMany, saveMany, oraz robić asocjację (czyli zapisywanie od drugiej strony).
Mam też nadzieję, że ogarniamy iż nasze commentable_type i commentable_id nie są nullable (nie użyliśmy nullablemorphs, zobaczmy w bazie danych na widok strukturalny) a co za tym idzie nie można ich zapisać zanim ich nie podepniemy do czegoś, a zatem saveMany czy associate, to trzeba będzie zrobić new Comment (bez save) albo użyć make.
Tutaj już tych podstaw tłumaczyć nie będziemy, i tak bardzo się staram krok po kroku tematy omawiać. Ok, następna komenda:
Artisan::command('comment-for-review {id}', function (int $id) {
$r = Review::findOrFail($id);
$c = new Comment();
$c->title = "Comment for Review {$id}";
$c->content = "Content about Review {$id}";
$r->comments()->save($c);
$this->comment("done");
});
Mamy się tym pobawić, zapełnić naszą bazę. Ok, mam nadzieję, że tę komendę rozumiemy:
Artisan::command('all-comments', function () {
$comments = Comment::whereHasMorph(
'commentable',
[Movie::class, Review::class]
)->get();
foreach($comments as $c){
$this->comment("Title: {$c->title} ID: {$c->id} ");
}
});
Teraz jeszcze dla Movie:
Artisan::command('movie-comments', function () {
$comments = Comment::whereHasMorph(
'commentable',
[Movie::class]
)->get();
foreach($comments as $c){
$this->comment("Title: {$c->title} ID: {$c->id} Movie_id: {$c->commentable_id}");
}
});
I dla review:
Artisan::command('review-comments', function () {
$comments = Comment::whereHasMorph(
'commentable',
[Review::class]
)->get();
foreach($comments as $c){
$this->comment("Title: {$c->title} ID: {$c->id} Review_id: {$c->commentable_id}");
}
});
Na tym poziomie to nie jest kurs podstawowego SQLa ani fasady DB, przerabialiśmy już to, więc mam nadzieję, że (nawet jeśli po pewnym namyśle) ta komenda też nie będzie dla nas trudna, co najwyżej ciekawa:
Artisan::command('cnt-each-type', function () {
$comments = DB::table('comments')
->selectRaw("count(*), commentable_type")
->groupBy("commentable_type")->get();
dd($comments);
});
Ok, policzyliśmy ile jest komentarzy dla każdego z typów. Teraz policzmy komentarze dla każdej recenzji, komentarze dla innych typów niż recenzja olewamy:
Artisan::command('cnt-r-type', function () {
$comments = DB::table('comments')
->selectRaw("count(*) as count, commentable_id as review_id")
->where("commentable_type", Review::class)
->groupBy("commentable_id")->get();
dd($comments);
});
A teraz policzymy ile komentarzy ma każdy film, komentarze innych typów niż film olewamy:
Artisan::command('cnt-m-type', function () {
$comments = DB::table('comments')
->selectRaw("count(*) as count, commentable_id as movie_id")
->where("commentable_type", Movie::class)
->groupBy("commentable_id")->get();
dd($comments);
});
Mam nadzieję, że relacje (w tym polimorficzne) stają się dla nas powoli jasne.