marketo_suite-1.0.x-dev/src/Plugin/MarketoHandler/DefaultMarketoHandler.php
src/Plugin/MarketoHandler/DefaultMarketoHandler.php
<?php
namespace Drupal\e3_marketo\Plugin\MarketoHandler;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Link;
use Drupal\Core\Template\Attribute;
use Drupal\e3_marketo\Entity\MarketoFormEntityInterface;
use Drupal\e3_marketo\Plugin\MarketoHandlerBase;
/**
* Default handler to build output for Marketo Forms.
*
* @MarketoHandler(
* id = "default_marketo_handler",
* label = @Translation("Default Marketo Handler"),
* description = @Translation("Default Marketo handler to attach a base Marketo form with prefill support."),
* bundles = {},
* priority = 100
* )
*/
class DefaultMarketoHandler extends MarketoHandlerBase {
/**
* Tracks Marketo instances on the page.
*
* This variable is necessary in case the same form is added several times on
* the page.
*
* @var array
*/
public static array $marketoInstances;
/**
* HTML class of Marketo Form.
*
* @var string
*/
protected string $htmlClass;
/**
* Current Marketo Form instance.
*
* For cases when same form is added multiple times on the page, this helps
* handlers to be aware of the exact instance we're working with.
*
* @var int
*/
protected int $instance;
/**
* {@inheritdoc}
*/
public function embedMarketoForm(MarketoFormEntityInterface $marketo_form, array &$build) : array {
$marketo_form_id = $marketo_form->getFormId();
$this->htmlClass = "marketo-form-{$marketo_form_id}";
// Do not embed the form if key Marketo settings are missing.
if (!$this->verifyMarketoSettings()) {
return [];
}
// Determine the current form instance.
$this->instance = $this->getMarketoFormInstance($build, $marketo_form_id);
// Only run the default processing if dynamic parameters has not been set or
// if they were mistakenly cleared by one of the plugins.
if (empty($build['marketo_form_embed']['#form_attributes'])
|| empty($build['marketo_form_embed']['#attached']['drupalSettings']['marketoForms'])) {
$build['marketo_form_embed'] = [
'#theme' => 'marketo_form_embed',
'#form_attributes' => $this->getMarketoFormAttributes($marketo_form),
'#marketo_form_id' => $marketo_form_id,
'#attached' => [
'library' => ['e3_marketo/marketo-forms'],
'drupalSettings' => [
'marketoForms' => $this->getMarketoScriptParameters($marketo_form),
],
],
];
}
else {
// Otherwise only update the dynamic parameters.
$this->alterScriptParameters($build['marketo_form_embed']['#attached']['drupalSettings']['marketoForms'][$this->htmlClass], $marketo_form);
}
static::$loadedMarketoSettings = $build['marketo_form_embed']['#attached']['drupalSettings']['marketoForms'];
return $build;
}
/**
* Determine Marketo Form instance of the current form.
*
* @param array $build
* Marketo Form entity build array.
* @param string $marketo_form_id
* Marketo form id.
*
* @return int
* Marketo instance ID.
*/
public function getMarketoFormInstance(array $build, string $marketo_form_id) : int {
if (empty($build['marketo_form_embed']['#form_attributes'])
|| empty($build['marketo_form_embed']['#attached']['drupalSettings']['marketoForms'])) {
// Set Marketo instance.
if (!isset(static::$marketoInstances[$marketo_form_id])) {
$request = $this->requestStack->getCurrentRequest();
if ($request->isXmlHttpRequest()) {
$instance = time();
}
else {
$instance = 0;
}
static::$marketoInstances[$marketo_form_id] = $instance;
}
else {
static::$marketoInstances[$marketo_form_id]++;
$instance = static::$marketoInstances[$marketo_form_id];
}
}
else {
$instance = static::$marketoInstances[$marketo_form_id];
}
return $instance;
}
/**
* Retrieve script parameters to pass into Marketo embed script.
*
* @param \Drupal\e3_marketo\Entity\MarketoFormEntityInterface $marketo_form
* Marketo form entity.
*
* @return array
* Array of parameters to add to drupalSettings.
*/
public function getMarketoScriptParameters(MarketoFormEntityInterface $marketo_form) : array {
$form_id = $marketo_form->getFormId();
$munchkin_id = $this->marketoConfig->get('munchkin_id');
$instance_host = $this->marketoConfig->get('instance_host');
// Submission callbacks.
$html_class = $this->htmlClass;
$submission_callbacks = $this->getSubmissionCallbacks($marketo_form);
if (empty($marketo_form->bundle)) {
return [];
}
/** @var \Drupal\e3_marketo\Entity\MarketoFormEntityBundle $marketo_bundle */
$marketo_bundle = $marketo_form->bundle->entity;
// Main params to pass into JS.
$result = [
'munchkinId' => $munchkin_id,
'instanceHost' => $instance_host,
'formId' => $form_id,
'loadErrorMessage' => $this->marketoConfig->get('load_error_message.value'),
'alternativeInstanceHost' => $this->marketoConfig->get('alt_instance_host'),
'entityWrapper' => '.marketo-form-entity-ajax-wrapper',
'formWrapper' => '.marketo-form',
'htmlClass' => $html_class,
'removeSourceStyles' => $marketo_bundle->getRemoveSourceStyles(),
$this->instance => [
'submissionCallbacks' => $submission_callbacks,
],
];
// If this form is referenced via component, check if any hidden fields have
// been set.
if (!empty($marketo_form->_referringItem)) {
$parent_entity = $marketo_form->_referringItem->getEntity();
if ($parent_entity->hasField('field_marketo_hidden_fields')) {
$hidden_fields = $this->getMarketoHiddenFields($parent_entity);
if ($hidden_fields) {
$result[$this->instance]['hiddenFields'] = $hidden_fields;
}
}
}
$this->alterScriptParameters($result, $marketo_form);
// Figure out if any redirects set up within Marketo should be skipped.
$non_default_callbacks_added = !empty($submission_callbacks) && !isset($submission_callbacks['default_marketo_handler']);
$default_with_thank_you = isset($submission_callbacks['default_marketo_handler']) && !empty($result['thankYouComponent']);
if ($non_default_callbacks_added || $default_with_thank_you) {
$result[$this->instance]['skipMarketoRedirects'] = TRUE;
}
$params[$html_class] = $result;
return $params;
}
/**
* Alter the list of parameters that will be sent to Marketo script.
*
* @param array $params
* Parameters list to alter.
* @param \Drupal\e3_marketo\Entity\MarketoFormEntityInterface $marketo_form
* Marketo Form entity.
*/
public function alterScriptParameters(array &$params, MarketoFormEntityInterface $marketo_form) {
// Nothing to do here in this handler, but the function stub needs to exist.
}
/**
* Retrieve a set of Html parameters to pass into Marketo template.
*
* @param \Drupal\e3_marketo\Entity\MarketoFormEntityInterface $marketo_form
* Marketo form entity.
*
* @return \Drupal\Core\Template\Attribute
* Html attributes to pass into template as 'form_attributes'.
*/
public function getMarketoFormAttributes(MarketoFormEntityInterface $marketo_form) : Attribute {
$html_class = $this->htmlClass;
$attributes = new Attribute();
$attributes->setAttribute('data-form-id', $marketo_form->getFormId());
$attributes->setAttribute('data-form-name', $marketo_form->getName());
$attributes->addClass(['marketo-form-load', $html_class]);
$attributes->setAttribute('data-instance', (string) $this->instance);
return $attributes;
}
/**
* Check that all required Marketo settings have been set.
*
* @return bool
* TRUE if all required settings are available, FALSE otherwise.
*/
public function verifyMarketoSettings() : bool {
if (!$this->marketoConfig->get('instance_host') || !$this->marketoConfig->get('munchkin_id')) {
$this->messenger->addError($this->t("Marketo Form could not be loaded, because some of the required Marketo Settings are missing. Please, visit the @link to fill them.", [
'@link' => Link::createFromRoute($this->t("Settings Page"), 'marketo_form.settings')->toString(),
]));
return FALSE;
}
else {
return TRUE;
}
}
/**
* Retrieve all hidden fields set for the Marketo Form.
*
* @param \Drupal\Core\Entity\FieldableEntityInterface $parent_entity
* Parent entity of the Marketo Form.
*
* @return array
* An object with field names as properties. This is the way Marketo expects
* the hidden fields data to be set.
*/
public function getMarketoHiddenFields(FieldableEntityInterface $parent_entity) : array {
$result = [];
// Check if any hidden fields have been set.
if (!$parent_entity->get('field_marketo_hidden_fields')->isEmpty()) {
foreach ($parent_entity->get('field_marketo_hidden_fields') as $hidden_field) {
$parent = !empty($hidden_field->entity) ? $hidden_field->entity : NULL;
if ($parent && $parent->hasField('field_hidden_field_name') && $parent->hasField('field_hidden_field_value')) {
$field_name = $parent->get('field_hidden_field_name')->value;
$field_value = $parent->get('field_hidden_field_value')->value;
$result[$field_name] = $field_value;
}
}
}
return $result;
}
/**
* Get the submission callbacks selected for this form.
*
* @param \Drupal\e3_marketo\Entity\MarketoFormEntityInterface $marketo_form
* Marketo form entity.
*/
public function getSubmissionCallbacks(MarketoFormEntityInterface $marketo_form) : array {
// Check for patent entity.
if (!empty($marketo_form->_referringItem)) {
$parent_entity = $marketo_form->_referringItem->getEntity();
if ($parent_entity && $parent_entity->hasField('field_submission_behavior')) {
$submission_behavior = $parent_entity->get('field_submission_behavior')->getString();
}
}
// If parent entity didn't provide a behavior, look for one on the form.
if (empty($submission_behavior)) {
$submission_behavior = $marketo_form->get('submission_behavior')->getString();
}
// Set submission callbacks.
if ($submission_behavior) {
try {
/** @var \Drupal\e3_marketo\Plugin\SubmissionBehaviorInterface $behavior */
$behavior = $this->submissionBehaviorManager->createInstance($submission_behavior);
}
catch (PluginException $e) {
return [];
}
return $behavior->getSubmissionCallbacks($marketo_form);
}
return [];
}
}
