Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 34 additions & 7 deletions ProcessMaker/Http/Controllers/Api/TaskController.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,19 @@
use ProcessMaker\Models\UserResourceView;
use ProcessMaker\Notifications\TaskReassignmentNotification;
use ProcessMaker\Query\SyntaxError;
use ProcessMaker\Repositories\ProcessExecutionRawRepository;
use ProcessMaker\SanitizeHelper;
use ProcessMaker\Traits\TaskControllerIndexMethods;

class TaskController extends Controller
{
use TaskControllerIndexMethods;

private function processExecutionRaw(): ProcessExecutionRawRepository
{
return app(ProcessExecutionRawRepository::class);
}

/**
* A whitelist of attributes that should not be
* sanitized by our SanitizeInput middleware.
Expand Down Expand Up @@ -336,28 +342,49 @@ public function show(ProcessRequestToken $task)
*/
public function update(Request $request, ProcessRequestToken $task)
{
if (!$task->relationLoaded('process')) {
$task->setRelation('process', $this->processExecutionRaw()->getProcessForAuthorizeRaw($task->process_id));
}
$this->authorize('update', $task);
if ($request->input('status') === 'COMPLETED') {
if ($task->status === 'CLOSED') {
return abort(422, __('Task already closed'));
}
// Skip ConvertEmptyStringsToNull and TrimStrings middlewares
$data = json_optimize_decode($request->getContent(), true);
$data = SanitizeHelper::sanitizeData($data['data'], null, $task->processRequest->do_not_sanitize ?? []);
$requestRow = $this->processExecutionRaw()->getProcessRequestRowForCompleteRaw($task->process_request_id);
$data = SanitizeHelper::sanitizeData($data['data'], null, $this->processExecutionRaw()->getDoNotSanitizeFromRowRaw($requestRow));

//Call the manager to trigger the start event
$process = $task->process;
$instance = $task->processRequest;
TaskDraft::moveDraftFiles($task);
$process = $this->processExecutionRaw()->getProcessForCompleteRaw($task->process_id);
$instance = $this->processExecutionRaw()->getProcessRequestFromRowRaw($requestRow);
$instance->setRelation('process', $process);
if ($processVersion = $this->processExecutionRaw()->getProcessVersionForCompleteRaw($requestRow->process_version_id ?? null)) {
$instance->setRelation('processVersion', $processVersion);
}
$task->setRelation('processRequest', $instance);
$task->setRelation('process', $process);

if ($this->processExecutionRaw()->taskHasDraftRaw($task->id)) {
TaskDraft::moveDraftFiles($task);
}

WorkflowManager::completeTask($process, $instance, $task, $data);

return new Resource($task->refresh());
$responseInstance = $this->processExecutionRaw()->getProcessRequestForResponseRaw($task->process_request_id);
$responseInstance->setRelation('process', $process);
$taskRefreshed = $this->processExecutionRaw()->refreshTaskRaw($task, $process, $responseInstance);

return new Resource($taskRefreshed);
} elseif (!empty($request->input('user_id'))) {
$process = $this->processExecutionRaw()->getProcessForReassignRaw($task->process_id);
$task->setRelation('process', $process);

$userToAssign = $request->input('user_id');
$comments = $request->input('comments');
$task->reassign($userToAssign, $request->user(), $comments);

$taskRefreshed = $task->refresh();

$taskRefreshed = $this->processExecutionRaw()->refreshTaskRaw($task, $process, $task->processRequest);
CaseUpdate::dispatchSync($task->processRequest, $taskRefreshed);

return new Resource($taskRefreshed);
Expand Down
23 changes: 20 additions & 3 deletions ProcessMaker/Jobs/BpmnAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,13 @@ private function lockInstance($instanceId)
for ($tries = 0; $tries < $maxRetries; $tries++) {
$currentLock = $this->currentLock($ids);
if (!$currentLock) {
if (ProcessRequest::find($instanceId)) {
if (ProcessRequest::query()->whereKey($instanceId)->exists()) {
$lock = $this->requestLock($ids);
} else {
throw new Exception('Unable to lock instance #' . $this->instanceId . ': Request does not exists');
}
} elseif ($lock->id == $currentLock->id) {
$instance = ProcessRequest::findOrFail($instanceId);
$instance = $this->findProcessRequestForBpmnAction($instanceId);
$this->activateLock($lock);

return $instance;
Expand Down Expand Up @@ -231,7 +231,7 @@ private function findInstanceWithRetry($instanceId)

for ($attempt = 0; $attempt < $totalAttempts; $attempt++) {
try {
$instance = ProcessRequest::findOrFail($instanceId);
$instance = $this->findProcessRequestForBpmnAction($instanceId);

return $instance;
} catch (ModelNotFoundException $e) {
Expand Down Expand Up @@ -344,6 +344,23 @@ private function mSleep($milliseconds)
usleep($microseconds);
}

/**
* Load ProcessRequest with relations used when wiring the BPMN engine (reduces N+1 during completeTask / other BPMN jobs).
*
* @param int|string $instanceId
*/
private function findProcessRequestForBpmnAction($instanceId): ProcessRequest
{
return ProcessRequest::query()
->with([
'process',
'processVersion',
'collaboration',
])
->whereKey($instanceId)
->firstOrFail();
}

public function __destruct()
{
$this->instance = null;
Expand Down
11 changes: 10 additions & 1 deletion ProcessMaker/Models/Process.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use ProcessMaker\Nayra\Managers\WorkflowManagerDefault;
use ProcessMaker\Nayra\Storage\BpmnDocument;
use ProcessMaker\Package\WebEntry\Models\WebentryRoute;
use ProcessMaker\Repositories\ProcessExecutionRawRepository;
use ProcessMaker\Rules\BPMNValidation;
use ProcessMaker\Traits\Exportable;
use ProcessMaker\Traits\ExtendedPMQL;
Expand Down Expand Up @@ -668,6 +669,14 @@ public function getNextUser(ActivityInterface $activity, ProcessRequestToken $to
return $this->checkAssignment($token->getInstance(), $activity, $assignmentType, $escalateToManager, $user ? User::where('id', $user)->first() : null, $token);
}

/**
* @deprecated Use ProcessExecutionRawRepository::getNextUserRaw()
*/
public function getNextUserRaw(ActivityInterface $activity, ProcessRequestToken $token)
{
return app(ProcessExecutionRawRepository::class)->getNextUserRaw($this, $activity, $token);
}

/**
* If user assignment is not valid reassign to Process Manager
*
Expand Down Expand Up @@ -708,7 +717,7 @@ private function checkAssignment(ProcessRequest $request, ActivityInterface $act
return $user;
}

private function scalateToManagerIfEnabled($user, $activity, $token, $assignmentType)
public function scalateToManagerIfEnabled($user, $activity, $token, $assignmentType)
{
if ($user) {
$assignmentProcess = self::where('name', self::ASSIGNMENT_PROCESS)->first();
Expand Down
8 changes: 6 additions & 2 deletions ProcessMaker/Models/ProcessRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -848,8 +848,12 @@ public function updateCatchEvents()
public function mergeLatestStoredData()
{
$store = $this->getDataStore();
$latest = self::select('data')->find($this->getId());
$this->data = $store->updateArray($latest->data);
// Read only the JSON column without hydrating a full ProcessRequest row (called often during BPMN transitions).
$latestData = static::query()->whereKey($this->getKey())->value('data');
if (!is_array($latestData)) {
$latestData = [];
}
$this->data = $store->updateArray($latestData);

return $this->data;
}
Expand Down
Loading
Loading