To audit attach and detach at the moment you'd have to call Auditable::auditAttach or Auditable::auditDetach. I have a solution to audit the attach/detach while the normal methods are called.
Would you be interested into a PR with this solution?
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use OwenIt\Auditing\Auditable;
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
use OwenIt\Auditing\Database\Relations\BelongsToManyAudit;
final class MyModel extends Model implements AuditableContract
{
use Auditable;
public function otherModels(): BelongsToMany
{
return BelongsToManyAudit::audit($this->belongsToMany(OtherModel::class));
}
}
<?php
declare(strict_types=1);
namespace OwenIt\Auditing\Database\Relations;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Facades\Event;
use OwenIt\Auditing\Contracts\Auditable;
use OwenIt\Auditing\Events\AuditCustom;
/**
* @property Model&Auditable $parent
*
* @method Collection getResults()
*
* @mixin BelongsToMany
*/
final class BelongsToManyAudit extends BelongsToMany
{
protected function __construct()
{
parent::__construct(...\func_get_args());
}
public static function audit(BelongsToMany $belongsToMany): static
{
return new self(
$belongsToMany->related->newQueryWithoutRelationships(),
$belongsToMany->parent,
$belongsToMany->table,
$belongsToMany->foreignPivotKey,
$belongsToMany->relatedPivotKey,
$belongsToMany->parentKey,
$belongsToMany->relatedKey,
$belongsToMany->relationName,
);
}
/**
* Audit attach to the parent of the relation.
*
* {@inheritdoc}
*
* @param array<string, mixed> $attributes
*/
public function attach($id, array $attributes = [], $touch = true): void
{
$old = $this->getResults()->toArray();
parent::attach($id, $attributes, $touch);
$this->auditEvent('attached', $old, $this->getResults()->toArray());
}
/**
* Audit detach from the parent of the relation.
*
* {@inheritdoc}
*/
public function detach($ids = null, $touch = true): int
{
$old = $this->getResults()->toArray();
$result = parent::detach($ids, $touch);
$this->auditEvent('detached', $old, $this->getResults()->toArray());
return $result;
}
/**
* @param array<string, mixed> $old
* @param array<string, mixed> $new
*/
private function auditEvent(string $eventName, array $old, array $new): void
{
/** @var Auditable $model */
$model = clone $this->parent;
if (!\property_exists($model, 'auditEvent') || !\property_exists($model, 'isCustomEvent') || !\property_exists($model, 'auditCustomOld') || !\property_exists($model, 'auditCustomNew')) {
return;
}
$model->auditEvent = $eventName;
$model->isCustomEvent = true;
$model->auditCustomOld = [$this->relationName => $old];
$model->auditCustomNew = [$this->relationName => $new];
Event::dispatch(AuditCustom::class, [$model]);
}
}
To audit attach and detach at the moment you'd have to call Auditable::auditAttach or Auditable::auditDetach. I have a solution to audit the attach/detach while the normal methods are called.
Would you be interested into a PR with this solution?
It works as follows: