Laravel本地作用域问题:如何获取商品的首个有效优惠券?
Laravel模型本地作用域:获取商品首个有效优惠券的正确实现
问题场景
现有Laravel的Product和Voucher模型,关联关系如下:
Product模型:
class Product extends Model { public function vouchers(): HasMany { return $this->hasMany(Voucher::class); } }
Voucher模型:
class Voucher extends Model { public function product(): BelongsTo { return $this->belongsTo(Product::class); } }
voucher表包含status字段,取值为active或inactive。需要实现获取某一商品的首个有效优惠券,但原本地作用域写法报错:
Property [vouchers] does not exist on the Eloquent builder instance.
原错误代码:
public function scopeActiveVouchers($query) { return $query->vouchers->first()->where('status', 'active'); }
错误原因
本地作用域的参数$query是Eloquent Builder实例,而vouchers是定义在Product模型上的关联方法,Builder对象无法直接访问该属性,必须通过调用关联方法(vouchers())来获取关联查询的Builder实例,再添加条件。
正确实现方案
方案1:为Product实例添加方法获取首个有效优惠券
如果需求是针对单个Product实例获取其首个有效优惠券,更适合定义模型方法而非本地作用域:
class Product extends Model { public function vouchers(): HasMany { return $this->hasMany(Voucher::class); } // 获取当前商品的首个有效优惠券 public function firstActiveVoucher() { return $this->vouchers()->where('status', 'active')->first(); } }
调用方式:
$product = Product::find($productId); $activeVoucher = $product->firstActiveVoucher();
方案2:使用本地作用域预加载首个有效优惠券
如果需要在查询Product时批量预加载每个商品的首个有效优惠券,可以定义如下本地作用域:
class Product extends Model { public function vouchers(): HasMany { return $this->hasMany(Voucher::class); } public function scopeWithFirstActiveVoucher($query) { return $query->with(['vouchers' => function ($q) { $q->where('status', 'active')->take(1); }]); } }
调用方式:
// 查询商品并预加载首个有效优惠券 $product = Product::withFirstActiveVoucher()->find($productId); // 获取首个有效优惠券 $activeVoucher = $product->vouchers->first();
补充说明
本地作用域的核心用途是约束Product模型的查询条件,比如筛选出存在有效优惠券的商品;而如果是获取单个商品的关联数据,直接定义模型方法会更直观。
内容的提问来源于stack exchange,提问作者wiwa1978
相关产品推荐
相关产品推荐

