$extraContext */ public function start( Tenant $tenant, ProviderConnection $connection, string $operationType, callable $dispatcher, ?User $initiator = null, array $extraContext = [], ): ProviderOperationStartResult { if ((int) $connection->tenant_id !== (int) $tenant->getKey()) { throw new InvalidArgumentException('ProviderConnection does not belong to the given tenant.'); } $definition = $this->registry->get($operationType); return DB::transaction(function () use ($tenant, $connection, $operationType, $dispatcher, $initiator, $extraContext, $definition): ProviderOperationStartResult { $lockedConnection = ProviderConnection::query() ->whereKey($connection->getKey()) ->lockForUpdate() ->firstOrFail(); $activeRun = OperationRun::query() ->where('tenant_id', $tenant->getKey()) ->active() ->where('context->provider_connection_id', (int) $lockedConnection->getKey()) ->orderByDesc('id') ->first(); if ($activeRun instanceof OperationRun) { if ($activeRun->type === $operationType) { return ProviderOperationStartResult::deduped($activeRun); } return ProviderOperationStartResult::scopeBusy($activeRun); } $context = array_merge($extraContext, [ 'provider' => $lockedConnection->provider, 'module' => $definition['module'], 'provider_connection_id' => (int) $lockedConnection->getKey(), 'target_scope' => [ 'entra_tenant_id' => $lockedConnection->entra_tenant_id, ], ]); $run = $this->runs->ensureRunWithIdentity( tenant: $tenant, type: $operationType, identityInputs: [ 'provider_connection_id' => (int) $lockedConnection->getKey(), ], context: $context, initiator: $initiator, ); $dispatched = false; if ($run->wasRecentlyCreated) { $this->invokeDispatcher($dispatcher, $run); $dispatched = true; } return ProviderOperationStartResult::started($run, $dispatched); }); } private function invokeDispatcher(callable $dispatcher, OperationRun $run): void { $ref = null; if (is_array($dispatcher) && count($dispatcher) === 2) { $ref = new ReflectionMethod($dispatcher[0], (string) $dispatcher[1]); } elseif (is_string($dispatcher) && str_contains($dispatcher, '::')) { [$class, $method] = explode('::', $dispatcher, 2); $ref = new ReflectionMethod($class, $method); } elseif ($dispatcher instanceof \Closure) { $ref = new ReflectionFunction($dispatcher); } elseif (is_object($dispatcher) && method_exists($dispatcher, '__invoke')) { $ref = new ReflectionMethod($dispatcher, '__invoke'); } if ($ref && $ref->getNumberOfParameters() >= 1) { $dispatcher($run); return; } $dispatcher(); } }