Background Information
I have a model called Product. The product can have 3 different stock methods: Serialize, Bulk and None.
- Serialize is chosen when every physical item has a barcode.
- Bulk is chosen when we care for the changes in quantities
- None is chosen when we want to include a product in the inventory but we don't care about the quantity.
What I want to do
I want to create those 3 models (Serialize, Bulk, None) and extend them to the Product. Then to be able to call something like Product::all() and get a collection like this:
Products [
0 => Serialize[...]
1 => Serialize[...]
2 => Bulk[...]
3 => None[...]
...
500 => Bulk[...]
]
My problem
How can I make laravel cast each object to their respective classes automatically?
My Model structure
Product model
class Product extends Model
{
use HasFactory;
/**
* The attributes that aren't mass assignable.
*
* @var array
*/
protected $guarded = ['id'];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'purchase_price' => MoneyCast::class,
'rental_price' => MoneyCast::class,
'is_active' => 'boolean',
];
/**
* Get active products only
*
* @param Builder $builder
*
* @return Builder
*/
public function scopeActive(Builder $builder): Builder
{
return $builder->where('is_active', '=', true);
}
/**
* Get inactive products only
*
* @param Builder $builder
*
* @return Builder
*/
public function scopeInactive(Builder $builder): Builder
{
return $builder->where('is_active', '=', false);
}
/**
* Set the name and slug when saving to database
*
* @param $value
*/
public function setNameAttribute($value): void
{
$this->attributes['name'] = $value;
$this->attributes['slug'] = Str::slug($value);
}
/**
* Get the products full name
*
* @return string
*/
public function getFullNameAttribute(): string
{
return $this->details
? "{$this->name} {$this->details}"
: $this->name;
}
/**
* Calculate total stocks
*
* @return int
*/
abstract public function getTotalAttribute(): int;
/**
* Calculate total stocks in quarantine
*
* @return int
*/
abstract public function getQuarantinedAttribute(): int;
/**
* Calculate available stocks
*
* @return int
*/
public function getAvailableAttribute(): int
{
return $this->getTotalAttribute() - $this->getQuarantinedAttribute();
}
/**
* Get brand
*
* @return BelongsTo
*/
public function brand(): BelongsTo
{
return $this->belongsTo(Brand::class);
}
/**
* Get category
*
* @return BelongsTo
*/
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
Serialize Model
class Serialize extends Product
{
/**
* Calculate total stocks
*
* @return int
*/
public function getTotalAttribute(): int
{
return $this->stocks()->count();
}
/**
* Calculate total stocks in quarantine
*
* @return int
*/
public function getQuarantinedAttribute(): int
{
return $this->stocks->sum(function ($stock) {
return $stock->repairs()
->where('status', '!=', last(Repair::STATUSES))
->where('is_working', '=', false)
->count();
});
}
/**
* Get associated stocks
*
* @return HasMany
*/
public function stocks(): HasMany
{
return $this->hasMany(Stock::class)->orderBy('barcode');
}
}
Bulk Model
class Bulk extends Product
{
/**
* Calculate total stocks
*
* @return int
*/
public function getTotalAttribute(): int
{
return $this->transactions()->sum('quantity');
}
/**
* Calculate total stocks in quarantine
*
* @return int
*/
public function getQuarantinedAttribute(): int
{
return $this->stocks->sum(function ($stock) {
return $stock->repairs()
->where('status', '!=', last(Repair::STATUSES))
->where('is_working', '=', false)
->sum('quantity');
});
}
/**
* Get bulk stock transactions.
*
* @return HasMany
*/
public function transactions(): HasMany
{
return $this->hasMany(Transaction::class)->latest();
}
}