Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
66.67% covered (warning)
66.67%
10 / 15
25.00% covered (danger)
25.00%
1 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
OwnedByVendor
66.67% covered (warning)
66.67%
10 / 15
25.00% covered (danger)
25.00%
1 / 4
13.70
0.00% covered (danger)
0.00%
0 / 1
 bootOwnedByVendor
81.82% covered (warning)
81.82%
9 / 11
0.00% covered (danger)
0.00%
0 / 1
5.15
 currentVendorId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 vendor
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 scopeForVendor
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace App\Models\Concerns;
4
5use App\Models\Vendor;
6use Illuminate\Database\Eloquent\Builder;
7
8/**
9 * Marks a model as vendor-ownable. A global scope limits queries to the
10 * current vendor's rows — but ONLY when the `multi_vendor` feature is on AND
11 * a vendor context is set. Single-store installs never notice it.
12 *
13 * Phase 12 wires the "current vendor" resolver; for now this is inert.
14 */
15trait OwnedByVendor
16{
17    public static function bootOwnedByVendor(): void
18    {
19        static::addGlobalScope('vendor', function (Builder $query) {
20            if (! feature('multi_vendor')) {
21                return;
22            }
23
24            $vendorId = static::currentVendorId();
25            if ($vendorId !== null) {
26                $query->where($query->getModel()->getTable() . '.vendor_id', $vendorId);
27            }
28        });
29
30        static::creating(function ($model) {
31            if (feature('multi_vendor') && $model->vendor_id === null) {
32                $model->vendor_id = static::currentVendorId();
33            }
34        });
35    }
36
37    /** The vendor the current request acts as, or null for the store owner. */
38    protected static function currentVendorId(): ?int
39    {
40        // Phase 12 replaces this with a real resolver (subdomain / logged-in
41        // vendor user / admin "acting as"). Inert until then.
42        return app()->bound('currentVendorId') ? app('currentVendorId') : null;
43    }
44
45    public function vendor()
46    {
47        return $this->belongsTo(Vendor::class);
48    }
49
50    public function scopeForVendor(Builder $query, int|Vendor|null $vendor): Builder
51    {
52        $id = $vendor instanceof Vendor ? $vendor->id : $vendor;
53
54        return $query->withoutGlobalScope('vendor')->where('vendor_id', $id);
55    }
56}