Cały czas ćwiczymy migracje i relacje. Tabele, które utworzymy będą nam potrzebne do następnych ćwiczeń, dobrze też wypracować sobie pewną rutynę w tworzeniu ich.
Ok, najpierw komenda:
php artisan make:model Movie -mfs
Teraz migracja:
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('movies', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('title')->unique();
$table->string('director');
$table->integer('length')->unsigned();
$table->dateTime('release_date');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('movies');
}
};
Mam nadzieję, że nadążamy. Teraz migrujemy i tworzymy tak samo model o nazwie Review:
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('reviews', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('author');
$table->text('content');
$table->tinyInteger('rating')->unsigned();
$table->foreignId('movie_id')->constrained(
table: 'movies', indexName: 'reviews_movie_id'
)->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('reviews');
}
};
Później omówimy sobie bardzo dokładnie, co tu się dzieje, na razie mam nadzieję, że nadążamy. Ok, migrujemy.
Teraz model Movie, fillable i relacja:
use App\Models\Review;
class Movie extends Model
{
use HasFactory;
protected $fillable = ["title", "director", "length", "release_date"];
public function reviews(){
return $this->hasMany(Review::class);
}
}
Druga strona relacji w modelu Review plus fillable:
use App\Models\Movie;
class Review extends Model
{
use HasFactory;
protected $fillable = ["author", "content", "rating"];
public function movie(){
return $this->belongsTo(Movie::class);
}
}
Wielokrotnie to omawialiśmy, pewne szczegóły jeszcze sobie wyjaśnimy. Powinno to być bardzo zrozumiałe i oczywiste. Teraz Factory dla Movie:
class MovieFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'title' => fake()->unique()->sentence(3),
'director' => fake()->name(),
'release_date' => fake()->dateTimeBetween('-10 years'),
'length' => fake()->numberBetween(60, 150),
];
}
}
Oraz Factory dla Review:
class ReviewFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'author' => fake()->name(),
'content' => fake()->paragraph(10),
'rating' => fake()->numberBetween(1,10)
];
}
}
I relacyjny seeder dla Movie:
use App\Models\Movie;
use App\Models\Review;
class MovieSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
Movie::factory()
->count(15)
->create()
->each(function($film){
$revs = Review::factory()
->count(random_int(1,5))
->make();
$film->reviews()->saveMany($revs);
});
}
}
Jedyna rzecz, której mamy prawo nie pamiętać to komenda odpalająca seedera, ja to zawsze zapominam:
php artisan db:seed --class=MovieSeeder
Ok, z rzeczy jeszcze nieomawianych mamy:
- indeks unique
- nowy zapis foreignFor
- tinyInteger zamiast integera
- własne pole dateTime
Mimo wszystko mamy wszelkie podstawy SQLowe, aby szybko przyswoić sobie, co tu się dzieje plus temat będę rozwijać w następnych lekcjach.