Skip to content

Trigger cookbook

Six recipes that use only supported calls. Each one says when the trigger has to run and why it works, so you can adapt it instead of copying it blind.

Nothing here queries the internal tables. Recipes that did that in the past were dropped: they couple a process to the schema and slow down under load.

Send a grid by email

When: after the task that fills the grid.

PMFSendMessage(
    $_SESSION["APPLICATION"],
    "no-reply@example.com",
    @@NotifyTo,
    "",
    "",
    "Summary of case " . @@CaseTitle,
    "grid-summary.html",
    ["Rows" => @@Rows]
);

Why it works: the eighth argument is the set of variables the template receives, and the template can repeat a block over a grid:

<table>
  <tr><td>Item</td><td>Amount</td></tr>
  @>Rows
  <tr><td>@#Item</td><td>@#Amount</td></tr>
  @<Rows
</table>

Pass the grid under the same name the template uses. If the block is not closed, the rest of the message is swallowed by the repetition.

Create a case with a status

When: any trigger that needs to start a case elsewhere.

$caseId = PMFNewCase(@@TargetProcessUid, $_SESSION["USER_LOGGED"], @@TargetTaskUid, [], "TO_DO");

Why it works: a case created without a status is a draft — it exists, but it is not in anyone's inbox. The fifth argument sets it: DRAFT or TO_DO. The function returns the new case id, or 0 when it fails, so check before using it.

Create a case on a self-service task

When: the target task is claimed by whoever takes it, not assigned by the process.

$caseId = PMFNewCase(@@TargetProcessUid, $usrUid, @@TargetTaskUid, [], "TO_DO");
if ($caseId) {
    PMFDerivateCase($caseId, 1, false, $usrUid);
}

Why it works: a self-service task only becomes available when the case reaches it, and a new case sits on its first delegation. Derivating with delIndex = 1 moves it once, which is what makes it appear in the pool. Passing the user avoids relying on the session when the trigger runs from a web entry.

Assign by value

When: the task uses value based assignment, so the assignee comes from a variable.

@@NextUser = $managerUid;
PMFDerivateCase($_SESSION["APPLICATION"], $_SESSION["INDEX"]);

Why it works: the assignment rule reads the variable when the case arrives, so the variable has to be set before the derivation, not after. If the variable holds a user id that cannot take the task, the case stops; the assignment rules of the task are the place to see which users are eligible.

Pause a case for a period

When: before or after a task, when the wait is decided by data rather than by a timer event.

$until = date("Y-m-d H:i:s", strtotime("+" . @%WaitDays . " days"));
PMFPauseCase($_SESSION["APPLICATION"], $_SESSION["INDEX"], $_SESSION["USER_LOGGED"], $until);

Why it works: an intermediate timer event waits a fixed time, decided in the diagram. PMFPauseCase takes the date at run time, so the wait can depend on a variable. An empty date pauses the case indefinitely.

Email the assignee when a case is unpaused

When: in a separate process that watches the unpause, not in the paused case itself.

$users = PMFGetNextAssignedUser($_SESSION["APPLICATION"], @@TasUid);
foreach ($users as $user) {
    if (!empty($user["USR_EMAIL"])) {
        PMFSendMessage(
            $_SESSION["APPLICATION"],
            "no-reply@example.com",
            $user["USR_EMAIL"],
            "", "",
            "Case resumed: " . @@CaseTitle,
            "case-resumed.html"
        );
    }
}

Why it works: a paused case runs no triggers until it resumes, so the email cannot be sent from inside it. The unpause fires the watching process, which reads the assignee and sends the message.

What is not here

  • Global counters and “global variables” — they relied on PM tables, which the product no longer offers.
  • Skipping the next task, reopening a case, routing all parallel tasks — they reached into APP_DELEGATION with SQL. They work until the schema changes, and they are slow.
  • Repeating a task N times — that is process design (a loop-around gateway or a multi-instance task), not trigger code.