Skip to main content

Activity Log

Rolix records role and membership mutations in role_activity_logs (config key rolix.tables.role_activity_log) through JobMetric\Rolix\Support\ActivityLogger. Failures inside the logger are swallowed so audit issues never break domain mutations.

Wiring

Role and Membership services call ActivityLogger::log() from afterCommon for mutating operations:

OperationRole actionMembership action
storecreate_roleassign_role
updateupdate_roleupdate_membership
destroydelete_roleremove_role
restorerestore_membership
forceDeleteforce_delete_membership

Role’s afterCommon logs for store, update, and destroy. Membership soft-delete / restore / force-delete follow the same logger with the matching CRUD operation name.


ActivityLogger::log

Namespace: JobMetric\Rolix\Support\ActivityLogger

public static function log(string $operation, Model $model, array $data = []): void

Parameters

ParamTypeDescription
$operationstringCRUD operation name (store, update, destroy, restore, forceDelete, or custom)
$modelModelSubject model (Role or Membership)
$dataarrayOptional payload; currently reads $data['reason'] into the log row

Behavior

  1. Resolves action via ActivityActions::fromOperation($operation, $model).
  2. Reads the authenticated user from Auth::user() as actor; if not a Model, uses actor_type = 'system' and actor_id = 0.
  3. Sets subject_type / subject_id from $model->getMorphClass() / $model->getKey().
  4. Fills target / context based on model type:
Subjecttarget_*context_*
Membershippersonable morphmemberable morph (may be null)
Rolerole morph (same as subject)null
other Modelsubject morph(not specially set)
  1. Captures ip_address from request()?->ip(), user_agent from request()?->userAgent(), and performed_at as now().
  2. Creates a RoleActivityLog row inside try/catch (Throwable) — exceptions are ignored.

Manual usage

use JobMetric\Rolix\Support\ActivityLogger;

ActivityLogger::log('store', $role, ['reason' => 'Imported from legacy ACL']);

ActivityActions

Namespace: JobMetric\Rolix\Support\ActivityActions

Constants

ConstantValue
CREATE_ROLEcreate_role
UPDATE_ROLEupdate_role
DELETE_ROLEdelete_role
ASSIGN_ROLEassign_role
REMOVE_ROLEremove_role
UPDATE_MEMBERSHIPupdate_membership
RESTORE_MEMBERSHIPrestore_membership
FORCE_DELETE_MEMBERSHIPforce_delete_membership

fromOperation

public static function fromOperation(string $operation, object $subject): string
$operationIf $subject instanceof RoleOtherwise (membership / other)
storecreate_roleassign_role
updateupdate_roleupdate_membership
destroydelete_roleremove_role
restorerestore_membershiprestore_membership
forceDeleteforce_delete_membershipforce_delete_membership
anything elsereturned as-is ($operation)returned as-is
use JobMetric\Rolix\Support\ActivityActions;
use JobMetric\Rolix\Models\Role;

ActivityActions::fromOperation('store', new Role); // create_role

RoleActivityLog Model

Namespace: JobMetric\Rolix\Models\RoleActivityLog
Table: config('rolix.tables.role_activity_log')

Fields

ColumnTypeDescription
idintPrimary key
actionstringCanonical action name (see constants)
actor_typestringMorph type of actor, or "system"
actor_idintActor id, or 0 for system
target_typestringMorph type of the target entity
target_idintTarget id
context_typestring|nullOptional context morph type
context_idint|nullOptional context morph id
subject_typestringMorph type of the mutated model
subject_idintSubject id
reasonstring|nullOptional reason from $data['reason']
ip_addressstring|nullRequest IP
user_agentstring|nullRequest user agent
performed_atdatetimeWhen the action occurred
created_at / updated_atdatetimeEloquent timestamps

Relations

MethodTypeMorph columns
actor()MorphToactor_type, actor_id
target()MorphTotarget_type, target_id
context()MorphTocontext_type, context_id
subject()MorphTosubject_type, subject_id

Resource accessors

AccessorEvent dispatched
actor_resourceActorResourceEvent
target_resourceTargetResourceEvent
context_resourceContextResourceEvent
subject_resourceSubjectResourceEvent

Listen and set $event->resource — same pattern as membership personable/memberable resources. See Events.

Example query

use JobMetric\Rolix\Models\RoleActivityLog;
use JobMetric\Rolix\Support\ActivityActions;

$logs = RoleActivityLog::query()
->where('action', ActivityActions::ASSIGN_ROLE)
->where('target_type', App\Models\User::class)
->where('target_id', 42)
->latest('performed_at')
->get();

foreach ($logs as $log) {
$actorJson = $log->actor_resource;
}