How-to library · Developer docs

How-to library

Task-shaped pages: a title that starts with a verb, the situation in a few lines, the steps, the working code in both engines, and why this way rather than another. Found from a search, done, and left.

How-to Forms

Create a person record from a form submission

Find the person by lower-cased email, update them if found (Record index 0, groups merged, names filled only when empty), create them otherwise. The actions were run on a development site with answers passed in place of a real submission.

Context

Context. Everyone who fills in the contact form should be a contact (a person record) in a Leads group, without a duplicate when they write in again. An email address belongs to one person across the whole account, so a job that simply creates a person fails the second time. The job below finds the person by address, updates them if found, and creates them otherwise. Its actions were run on a development site, with the answers passed in place of a real submission, including a repeat with the same address in different capitals.

Steps

  1. Create the Leads group, and put its id in site data as leads-group-id on each environment.
  2. In Customization › Orchestration, create a job Form: contact → person, limited to the site, asynchronous, with an entity event trigger: form submissions, Completed, parent record id the contact form's id.
  3. Retrieve records find-person: entity people, limit 1, criteria {"email": "{strtolower(trim($event->getRecord()->data['email']))}"}.
  4. Condition known-person, template {if $runData->get('find-person')->record}{$result->setMatching(true)}{/if}. Inside it, Update record update-person: source find-person, Record index 0, data from the first template below.
  5. Add an Else branch, and inside it Create record create-person: entity people, data from the second template.
  6. Submit the form twice on a development site with the same address, and check there is one person, in Leads.

Code

The update, which fills only empty names and adds the group to the ones the person already has:

Template code
{$answers = $event->getRecord()->data}
{$person = $runData->get('find-person')->record}
{$data = []}
{$firstName = trim($answers['firstName']|default:'')}
{$lastName = trim($answers['lastName']|default:'')}
{if !$person->getFirstName() && $firstName != ''}{$data['firstName'] = $firstName}{/if}
{if !$person->getLastName() && $lastName != ''}{$data['lastName'] = $lastName}{/if}
{$groups = []}
{foreach $person->getGroups() as $group}{$groups[] = $group->getId()}{/foreach}
{$leads = $siteData->get('leads-group-id')|intval}
{if !in_array($leads, $groups)}{$groups[] = $leads}{/if}
{$data['groups'] = $groups}
{$data|json_encode}
{% set answers = event.getRecord().data %}
{% set person = runData.get('find-person').record %}
{% set data = {} %}
{% set firstName = answers.firstName|default('')|trim %}
{% set lastName = answers.lastName|default('')|trim %}
{% if not person.getFirstName() and firstName != '' %}{% set data = data|merge({firstName: firstName}) %}{% endif %}
{% if not person.getLastName() and lastName != '' %}{% set data = data|merge({lastName: lastName}) %}{% endif %}
{% set groups = [] %}
{% for group in person.getGroups() %}{% set groups = groups|merge([group.getId()]) %}{% endfor %}
{% set leads = siteData.get('leads-group-id')|integer %}
{% if leads not in groups %}{% set groups = groups|merge([leads]) %}{% endif %}
{{ data|merge({groups: groups})|json_encode }}

The create:

Template code
{$answers = $event->getRecord()->data}
{$data = [
  'email' => strtolower(trim($answers['email'])),
  'firstName' => trim($answers['firstName']|default:''),
  'lastName' => trim($answers['lastName']|default:''),
  'externalId' => "form-submission:{$event->getRecordId()}",
  'groups' => [$siteData->get('leads-group-id')|intval]
]}
{$data|json_encode}
{% set answers = event.getRecord().data %}
{{ {
  email: answers.email|trim|lower,
  firstName: answers.firstName|default('')|trim,
  lastName: answers.lastName|default('')|trim,
  externalId: 'form-submission:' ~ event.getRecordId(),
  groups: [siteData.get('leads-group-id')|integer]
}|json_encode }}

Why this and not that

  • Record index 0. It counts from 0 and defaults to 1, so with the default the update fails with "Index 1 does not exist in collection with 1 elements".
  • Groups are merged by hand. Sending groups replaces the person's groups. Sending only the Leads id would take them out of every other group, the newsletter included.
  • Lower-cased addresses. Every person the form creates is stored the same way, whatever capitals the visitor typed, and the search for an existing person does not depend on how the database compares case.
  • Names filled, never overwritten. A member may have corrected their own name; a form typed in a hurry should not undo it.
  • No guard shown here. Add the email guard from Creating records as the first action if the form's email field is optional or might hold something that is not an address. That page also covers newsletter consent, leads with their own fields, and custom entity records.
Go deeper

Was this page helpful?

Your answer goes to the docs team.