I'm trying to take advantage of the Laravel's Polymorphic Relationships
I'm building an app where I have 3 tables: products, expenses and hunts.
Each product, expense or hunt belongs to a category. I used to have 3 other different tables product_categories, expenses_categories and hunts_categories but I didn't like doing it this way so I did a little bit of research and found about this Polimorphic Relationships thing but I'm not really sure how to use it.
I've create a new category table with the following columns
$table->id();
$table->string('name');
$table->integer('categorizable_id');
$table->string('categorizable_type');
$table->foreignId('icon_id')->constrained();
My models looks like
class Product extends Model
{
public function category () {
return $this->morphOne(Category::class, 'categorizable');
}
}
class Expense extends Model
{
public function category () {
return $this->morphOne(Category::class, 'categorizable');
}
}
class Hunt extends Model
{
public function category () {
return $this->morphOne(Category::class, 'categorizable');
}
}
class Category extends Model
{
public function icon () {
return $this->belongsTo(Icon::class);
}
public function categorizable () {
return $this->morphTo();
}
}
I only want 5 categories for the expenses table so I'm seeding them directly to the database but products categories and hunt categories are created by the user
In my CategorySeeder.php file I have the following function
public function run()
{
DB::table('categories')->insert([
['name' => 'Advertising', 'icon_id' => 1, 'categorizable_id' => ?, 'categorizable_type' => 'App\Models\Expense'],
['name' => 'Utilities', 'icon_id' => 2],
['name' => 'Shopping', 'icon_id' => 3],
['name' => 'Payroll', 'icon_id' => 4],
['name' => 'Other', 'icon_id' => 5]
]);
}
Since I want those categories before creating any expense. What should I do with categorizable_id column?
CodePudding user response:
You don't need to use polymorphic relationships for this. You can simply have a categories table:
$table->id();
$table->string('name');
$table->foreignId('icon_id')->constrained();
And then have a category_id column on your product, expenses, and hunts tables:
$table->foreignId('category_id')->constrained();
Each of your Product, Expense, and Hunt models would have a category method:
public function category()
{
return $this->belongsTo(Category::class);
}
And then your Category model could have something like this:
public function products()
{
return $this->hasMany(Product::class);
}
public function expenses()
{
return $this->hasMany(Expense::class);
}
public function hunts()
{
return $this->hasMany(Hunt::class);
}
A polymorphic relationship would be useful if you had a Note model, for example, which could belong to either a product or an expense. In that case, you would have the columns notable_type and notable_id on your notes table, and then use morphOne on your Product and Expense models.
