W sumie prosta relacja, ale zostawiłem ją na teraz, kiedy już dobrze rozumiemy wiele relacji. Do dzieła.
Ok, nie będę wszystkiego od początku tłumaczyć, powinniśmy już ogarniać kod na szybko. Migracja Category:
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('categories');
}
};
Migracja Type:
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('types', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->unsignedBigInteger('category_id')->nullable(true);
$table->string('name');
$table->foreign('category_id')
->references('id')
->on('categories')
->onDelete('cascade')
->onUpdate('cascade');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('types');
}
};
Migracja Item:
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('items', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->unsignedBigInteger('type_id')->nullable(true);
$table->string('name');
$table->foreign('type_id')
->references('id')
->on('types')
->onDelete('cascade')
->onUpdate('cascade');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('items');
}
};
Model Category:
class Category extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function types(){
return $this->hasMany(Type::class);
}
public function items()
{
return $this->hasManyThrough(Item::class, Type::class);
}
}
Model Type:
class Type extends Model
{
protected $fillable = ['name'];
use HasFactory;
public function items(){
return $this->hasMany(Item::class);
}
public function category(){
return $this->belongsTo(Category::class);
}
}
Model Item:
class Item extends Model
{
protected $fillable = ['name'];
use HasFactory;
public function type(){
return $this->belongsTo(Type::class);
}
}
Utwórz kategorię:
Artisan::command('category {num}', function (int $num) {
$cat = new Category();
$cat->name = "Category {$num}";
$cat->save();
$this->comment("Done");
});
Utwórz typ do kategorii:
Artisan::command('type {num} {cat}', function (int $num, int $cat) {
$type = new Type();
$type->name = "Type {$num} for cat {$cat}";
$cat = Category::findOrFail($cat);
$cat->types()->save($type);
$this->comment("Done");
});
Utwórz Item do typu:
Artisan::command('item {n} {typeid}', function (string $n, int $typeid) {
$item = new Item();
$item->name = "{$n}";
$type = Type::findOrFail($typeid);
$type->items()->save($item);
$this->comment("Done");
});
Tworzymy dużo różnych. Różne typy w różnych kategoriach, różne itemy. Jak już mamy, to finalna komenda, sprawdzająca, czy działa:
Artisan::command('category-items {id}', function (int $id) {
$cat = Category::with('items')->findOrFail($id);
$this->comment("Category name: {$cat->name}");
foreach($cat->items as $i){
$this->comment("Item: {$i->name}");
}
});
Jak widać, działa. Tak samo było z relacją hasOneThrough. Jedyna różnica, że tam pośrednik miał hasOne, tutaj pośrednik ma hasMany. Tamto ogarnęliśmy to to też powinno być dla nas proste.