Guide 09 · Developer docs

Automation, jobs and integration

A job is a trigger, conditions and an ordered list of actions, set up under Customization › Orchestration in the admin; jobs were called hooks before the module was renamed, and the API's routes keep that name. What starts a job, what it can do, branches and loops, email, scheduled work, integrations with other systems, and every event and action.

L2–L3
Unit 03 · What a job does

Files, PDFs and certificates

Create File saves output into the file manager, Merge Files joins files end to end, and Merge PDFs joins PDFs into one. Where the files go, how long they last, what each action can take as input, and a certificate built from all three.

Who this is for. Anyone producing exports, documents or certificates from a job. Afterwards you can save a file where it will last, combine parts into one, and know which conversions need a service outside the platform.

Create File

Field (admin label)Takes
Source actionAn earlier Render Template (its content) or HTTP Request (its response body). Empty means the template below is rendered instead
Template File, Template CodeThe content, when there is no source action
Output filenameTemplate code. A name with no / is saved in the run's own folder; a path such as /exports/products.csv is saved there. Empty means action- and the action's id
Expires after daysThe file is deleted that many days later. Empty means it never expires

A file whose content is an image is saved as an image, anything else as a file. An existing file at the same path is replaced, so a nightly export with a fixed name always holds the latest run. The action leaves filename, record, and file or image, whose getPath() gives the path to link to.

Two cases fail. An HTTP Request whose answer was JSON or XML has no body to save, because the answer was parsed into responseData: the action fails with HTTP response body did not contain any content. And a source action that produced nothing fails the same way.

Where files go, and how long they last

The run's own folder is /hooks/<job name, slugified and cut to 30 characters>/<run id> in the file manager, and it is deleted with the run. With Batch persistence set to On Error, every file a successful run saved in its own folder disappears as the run ends; with Always, after 30 days. Give any file that must outlive the run a path of its own, and set Expires after days to the time it is really needed.

Files are served at /files/ followed by their path. When a file is for one person, such as a certificate, give it a name nobody can guess from a record id: the record id and a random part.

Template code
/certificates/{$event->getRecordId()}-{bin2hex(openssl_random_pseudo_bytes(8))}.pdf
/certificates/{{ event.getRecordId() }}-{{ random(100000000, 999999999) }}{{ random(100000000, 999999999) }}.pdf

Later actions read the path back from the Create File result, so nothing needs to reproduce the name.

Merge Files

Joins files end to end into a new one: the parts of a large CSV written by a loop, for example. The Files source is either criteria, which search the file manager and are limited to the run's own folder unless they name a folder or path, or template code that lists the paths:

Template code
{$mergeFilesHelper->addPath('/exports/parts/header.csv')}
{$mergeFilesHelper->addPaths(['/exports/parts/1.csv', '/exports/parts/2.csv'])}
{% do mergeFilesHelper.addPath('/exports/parts/header.csv') %}
{% do mergeFilesHelper.addPaths(['/exports/parts/1.csv', '/exports/parts/2.csv']) %}

It takes an Output filename and Expires after days as Create File does, and leaves the joined file. If the physical files are missing, it creates an empty file rather than failing, so check the size of what it made before sending it on.

Merge PDFs

Joins existing PDF files into one PDF, in the same way and with the same fields. It converts nothing: given anything but PDFs, it does not produce a usable PDF. No action turns HTML into a PDF.

A certificate, end to end

Because no action converts HTML, a certificate needs an HTML-to-PDF service in the middle:

  1. Render Template certificate-html: the certificate's HTML from a template in templates/hooks/, with the member's name and the course.
  2. HTTP Request convert-to-pdf: a POST of {$runData->get('certificate-html')->content} to the conversion service, its key read from site data. The service answers with the PDF itself, which is not JSON, so it is kept as the response body.
  3. Create File save-certificate: source action convert-to-pdf, the filename above, an expiry such as 90 days.
  4. Merge PDFs, if the certificate carries a standard second page such as terms: the new file and the terms PDF, joined.
  5. Send Email with a link to the file: https://{$site->getPrimaryHostname()}{$runData->get('save-certificate')->file->getPath()}. Mail from a job has no attachments.

Step by step, with the template: Generate a PDF certificate from a template. The email that carries the link is the second of the three worked emails.

Go deeper

Was this page helpful?

Your answer goes to the docs team.