You're right to look for a way to log attach/detach events for your many-to-many relationships, but the issue is that Eloquent models do not have pivotAttached or pivotDetached methods. These are not native Eloquent features, nor are they provided by popular packages like owen-it/laravel-auditing.
Why the Error?
Call to undefined method App\Models\Contract::pivotAttached()
Eloquent models can't "listen" for relationship attaches/detaches, because attaching and detaching is done via the relationship object, not the model itself (e.g., $contract->files()->attach(...)), and no events are fired on those actions by default.
How To Audit Many-to-Many Relation Events
Solution 1: Wrap Attach/Detach in Your Own Method
The most reliable and common approach is to never call attach/detach directly in your controllers/services. Always use your own methods so you can place the audit code there.
Example:
// In your Contract model:
public function attachFile($fileId, $attributes = [])
{
$this->files()->attach($fileId, $attributes);
Audit::create([
'user_id' => auth()->id(),
'event' => 'attached',
'auditable_id' => $this->id,
'auditable_type' => self::class,
'old_values' => [],
'new_values' => ['file_id' => $fileId],
'url' => request()->fullUrl(),
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
'tags' => 'relationship_change',
]);
}
public function detachFile($fileId)
{
$this->files()->detach($fileId);
Audit::create([
'user_id' => auth()->id(),
'event' => 'detached',
'auditable_id' => $this->id,
'auditable_type' => self::class,
'old_values' => ['file_id' => $fileId],
'new_values' => [],
'url' => request()->fullUrl(),
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
'tags' => 'relationship_change',
]);
}
Note: Don't call
->files()->attach()directly. Use$contract->attachFile($id)instead.
Solution 2: Use Eloquent Events on Pivot Model (if you have one)
If your pivot table has its own Model (a custom pivot model), you can use its model events.
Example:
class ContractFile extends Pivot // extends Illuminate\Database\Eloquent\Relations\Pivot
{
protected static function booted()
{
static::created(function ($pivot) {
// Log attach here
});
static::deleted(function ($pivot) {
// Log detach here
});
}
}
// In your Contract model:
public function files()
{
return $this->belongsToMany(File::class)
->using(ContractFile::class);
}
Solution 3: Override the Relationship
If you always want this to happen, you can create a custom relation class and override the attach/detach methods. This is an advanced solution and rarely needed for most projects.
References
Summary
static::pivotAttacheddoes not exist—that's why you get the error.- Wrap attach/detach in your own methods so you can log the audit.
- Optionally, use custom Pivot models if your pivot table has extra columns or you need events.
This is a common request, but there's no native Eloquent event for attach or detach.
Let me know if you'd like example code for a service-based approach or customizing the pivot model further!