/** * @param PageDisplayEvent $event */ public function onPageDisplay(PageDisplayEvent $event) { $content = $event->getContent(); $page = $event->getPage(); $regex = '/' . $this->formRegex . '/i'; preg_match_all($regex, $content, $matches); if (count($matches[0])) { foreach ($matches[1] as $k => $id) { $form = $this->formModel->getEntity($id); if ($form !== null && ($form->isPublished(false) || $this->security->hasEntityAccess('form:forms:viewown', 'form:forms:viewother', $form->getCreatedBy()))) { $formHtml = $form->isPublished() ? $this->formModel->getContent($form) : '<div class="mauticform-error">' . $this->translator->trans('mautic.form.form.pagetoken.notpublished') . '</div>'; //add the hidden page input $pageInput = "\n<input type=\"hidden\" name=\"mauticform[mauticpage]\" value=\"{$page->getId()}\" />\n"; $formHtml = preg_replace('#</form>#', $pageInput . '</form>', $formHtml); //pouplate get parameters //priority populate value order by: query string (parameters) -> with lead if (!$form->getInKioskMode()) { $this->formModel->populateValuesWithLead($form, $formHtml); } $this->formModel->populateValuesWithGetParameters($form, $formHtml); $content = preg_replace('#{form=' . $id . '}#', $formHtml, $content); } else { $content = preg_replace('#{form=' . $id . '}#', '', $content); } } } $event->setContent($content); }
/** * @param $formId * @param bool $asTokens * * @return array */ protected function getFormFields($formId, $asTokens = true) { $fields = $this->fieldModel->getSessionFields($formId); $viewOnly = $this->formModel->getCustomComponents()['viewOnlyFields']; $choices = []; foreach ($fields as $f) { if (in_array($f['type'], $viewOnly)) { continue; } $choices[$asTokens ? '{formfield=' . $f['alias'] . '}' : $f['alias']] = $f['label']; } return $choices; }
/** * Get a list of source choices * * @param $sourceType * * @return array */ public function getSourceLists($sourceType = null) { $choices = array(); switch ($sourceType) { case 'lists': case null: $choices['lists'] = array(); $lists = empty($options['global_only']) ? $this->leadListModel->getUserLists() : $this->leadListModel->getGlobalLists(); foreach ($lists as $list) { $choices['lists'][$list['id']] = $list['name']; } case 'forms': case null: $choices['forms'] = array(); $viewOther = $this->security->isGranted('form:forms:viewother'); $repo = $this->formModel->getRepository(); $repo->setCurrentUser($this->user); $forms = $repo->getFormList('', 0, 0, $viewOther, 'campaign'); foreach ($forms as $form) { $choices['forms'][$form['id']] = $form['name']; } } foreach ($choices as &$typeChoices) { asort($typeChoices); } return $sourceType == null ? $choices : $choices[$sourceType]; }
/** * @param $focus * @param bool $preview * @param bool $ignoreMinify * * @return string */ public function generateJavascript($focus, $preview = false, $ignoreMinify = false) { if ($focus instanceof Focus) { $focus = $focus->toArray(); } if (!empty($focus['form'])) { $form = $this->formModel->getEntity($focus['form']); } else { $form = null; } if ($preview) { $content = ['style' => '', 'html' => $this->templating->getTemplating()->render('MauticFocusBundle:Builder:content.html.php', ['focus' => $focus, 'form' => $form, 'preview' => $preview])]; } else { // Generate link if applicable $url = ''; if ($focus['type'] == 'link') { $trackable = $this->trackableModel->getTrackableByUrl($focus['properties']['content']['link_url'], 'focus', $focus['id']); $url = $this->trackableModel->generateTrackableUrl($trackable, ['channel' => ['focus', $focus['id']]]); } $content = $this->templating->getTemplating()->render('MauticFocusBundle:Builder:generate.js.php', ['focus' => $focus, 'form' => $form, 'preview' => $preview, 'ignoreMinify' => $ignoreMinify, 'clickUrl' => $url]); if (!$ignoreMinify) { $content = \JSMin::minify($content); } } return $content; }
/** * Compile events for the lead timeline * * @param LeadTimelineEvent $event */ public function onTimelineGenerate(LeadTimelineEvent $event) { // Set available event types $eventTypeKey = 'form.submitted'; $eventTypeName = $this->translator->trans('mautic.form.event.submitted'); $event->addEventType($eventTypeKey, $eventTypeName); if (!$event->isApplicable($eventTypeKey)) { return; } /** @var \Mautic\FormBundle\Entity\SubmissionRepository $submissionRepository */ $submissionRepository = $this->em->getRepository('MauticFormBundle:Submission'); $rows = $submissionRepository->getSubmissions($event->getQueryOptions()); // Add total to counter $event->addToCounter($eventTypeKey, $rows); if (!$event->isEngagementCount()) { // Add the submissions to the event array foreach ($rows['results'] as $row) { // Convert to local from UTC $form = $this->formModel->getEntity($row['form_id']); $submission = $submissionRepository->getEntity($row['id']); $event->addEvent(['event' => $eventTypeKey, 'eventLabel' => ['label' => $form->getName(), 'href' => $this->router->generate('mautic_form_action', ['objectAction' => 'view', 'objectId' => $form->getId()])], 'eventType' => $eventTypeName, 'timestamp' => $row['dateSubmitted'], 'extra' => ['submission' => $submission, 'form' => $form, 'page' => $this->pageModel->getEntity($row['page_id'])], 'contentTemplate' => 'MauticFormBundle:SubscribedEvents\\Timeline:index.html.php', 'icon' => 'fa-pencil-square-o']); } } }
/** * @param CampaignExecutionEvent $event */ public function onCampaignTriggerCondition(CampaignExecutionEvent $event) { $lead = $event->getLead(); if (!$lead || !$lead->getId()) { return $event->setResult(false); } $operators = $this->formModel->getFilterExpressionFunctions(); $form = $this->formModel->getRepository()->findOneById($event->getConfig()['form']); if (!$form || !$form->getId()) { return $event->setResult(false); } $result = $this->formSubmissionModel->getRepository()->compareValue($lead->getId(), $form->getId(), $form->getAlias(), $event->getConfig()['field'], $event->getConfig()['value'], $operators[$event->getConfig()['operator']]['expr']); $event->setChannel('form', $form->getId()); return $event->setResult($result); }
/** * @deprecated - added for BC; to be removed in 3.0 * * @param Action[] $actions * @param SubmissionEvent $event * @param $validationErrors * @param $lastAlias Because prior to now the last alias was used regardless */ protected function validateActionCallbacks(SubmissionEvent $event, &$validationErrors, $lastAlias) { $args = ['post' => $event->getPost(), 'server' => $event->getServer(), 'factory' => $this->factory, 'submission' => $event->getSubmission(), 'fields' => $event->getFields(), 'form' => $event->getSubmission()->getForm(), 'tokens' => $event->getTokens()]; $actions = $event->getSubmission()->getForm()->getActions(); $availableActions = $this->formModel->getCustomComponents()['actions']; foreach ($actions as $action) { $key = $action->getType(); if (!isset($availableActions[$key])) { continue; } $settings = $availableActions[$key]; $args['action'] = $action; $args['config'] = $action->getProperties(); if (array_key_exists('validator', $settings)) { $callback = $settings['validator']; if (is_callable($callback)) { if (is_array($callback)) { $reflection = new \ReflectionMethod($callback[0], $callback[1]); } elseif (strpos($callback, '::') !== false) { $parts = explode('::', $callback); $reflection = new \ReflectionMethod($parts[0], $parts[1]); } else { $reflection = new \ReflectionMethod(null, $callback); } $pass = []; foreach ($reflection->getParameters() as $param) { if (isset($args[$param->getName()])) { $pass[] = $args[$param->getName()]; } else { $pass[] = null; } } list($validated, $validatedMessage) = $reflection->invokeArgs($this, $pass); if (!$validated) { $validationErrors[$lastAlias] = $validatedMessage; } } } } unset($args, $actions, $availableActions); }
/** * Set a widget detail when needed. * * @param WidgetDetailEvent $event */ public function onWidgetDetailGenerate(WidgetDetailEvent $event) { $this->checkPermissions($event); $canViewOthers = $event->hasPermission('form:forms:viewother'); if ($event->getType() == 'submissions.in.time') { $widget = $event->getWidget(); $params = $widget->getParams(); if (!$event->isCached()) { $event->setTemplateData(['chartType' => 'line', 'chartHeight' => $widget->getHeight() - 80, 'chartData' => $this->formSubmissionModel->getSubmissionsLineChartData($params['timeUnit'], $params['dateFrom'], $params['dateTo'], $params['dateFormat'], $canViewOthers)]); } $event->setTemplate('MauticCoreBundle:Helper:chart.html.php'); $event->stopPropagation(); } if ($event->getType() == 'top.submission.referrers') { if (!$event->isCached()) { $params = $event->getWidget()->getParams(); if (empty($params['limit'])) { // Count the pages limit from the widget height $limit = round(($event->getWidget()->getHeight() - 80) / 35 - 1); } else { $limit = $params['limit']; } $referrers = $this->formSubmissionModel->getTopSubmissionReferrers($limit, $params['dateFrom'], $params['dateTo'], $canViewOthers); $items = []; // Build table rows with links if ($referrers) { foreach ($referrers as &$referrer) { $row = [['value' => $referrer['referer'], 'type' => 'link', 'external' => true, 'link' => $referrer['referer']], ['value' => $referrer['submissions']]]; $items[] = $row; } } $event->setTemplateData(['headItems' => [$event->getTranslator()->trans('mautic.form.result.thead.referrer'), $event->getTranslator()->trans('mautic.form.graph.line.submissions')], 'bodyItems' => $items, 'raw' => $referrers]); } $event->setTemplate('MauticCoreBundle:Helper:table.html.php'); $event->stopPropagation(); } if ($event->getType() == 'top.submitters') { if (!$event->isCached()) { $params = $event->getWidget()->getParams(); if (empty($params['limit'])) { // Count the pages limit from the widget height $limit = round(($event->getWidget()->getHeight() - 80) / 35 - 1); } else { $limit = $params['limit']; } $submitters = $this->formSubmissionModel->getTopSubmitters($limit, $params['dateFrom'], $params['dateTo'], $canViewOthers); $items = []; // Build table rows with links if ($submitters) { foreach ($submitters as &$submitter) { $name = $submitter['lead_id']; $leadUrl = $this->router->generate('mautic_contact_action', ['objectAction' => 'view', 'objectId' => $submitter['lead_id']]); if ($submitter['firstname'] || $submitter['lastname']) { $name = trim($submitter['firstname'] . ' ' . $submitter['lastname']); } elseif ($submitter['email']) { $name = $submitter['email']; } $row = [['value' => $name, 'type' => 'link', 'link' => $leadUrl], ['value' => $submitter['submissions']]]; $items[] = $row; } } $event->setTemplateData(['headItems' => [$event->getTranslator()->trans('mautic.form.lead'), $event->getTranslator()->trans('mautic.form.graph.line.submissions')], 'bodyItems' => $items, 'raw' => $submitters]); } $event->setTemplate('MauticCoreBundle:Helper:table.html.php'); $event->stopPropagation(); } if ($event->getType() == 'created.forms') { if (!$event->isCached()) { $params = $event->getWidget()->getParams(); if (empty($params['limit'])) { // Count the forms limit from the widget height $limit = round(($event->getWidget()->getHeight() - 80) / 35 - 1); } else { $limit = $params['limit']; } $forms = $this->formModel->getFormList($limit, $params['dateFrom'], $params['dateTo'], [], ['canViewOthers' => true]); $items = []; // Build table rows with links if ($forms) { foreach ($forms as &$form) { $formUrl = $this->router->generate('mautic_form_action', ['objectAction' => 'view', 'objectId' => $form['id']]); $row = [['value' => $form['name'], 'type' => 'link', 'link' => $formUrl]]; $items[] = $row; } } $event->setTemplateData(['headItems' => [$event->getTranslator()->trans('mautic.dashboard.label.title')], 'bodyItems' => $items, 'raw' => $forms]); } $event->setTemplate('MauticCoreBundle:Helper:table.html.php'); $event->stopPropagation(); } }
/** * @param MauticEvents\CommandListEvent $event */ public function onBuildCommandList(MauticEvents\CommandListEvent $event) { if ($this->security->isGranted(['form:forms:viewown', 'form:forms:viewother'], 'MATCH_ONE')) { $event->addCommands('mautic.form.forms', $this->formModel->getCommandList()); } }
/** * @param $post * @param $server * @param Form $form * * @return boolean|string false if no error was encountered; otherwise the error message */ public function saveSubmission($post, $server, Form $form) { $fieldHelper = new FormFieldHelper($this->translator); //everything matches up so let's save the results $submission = new Submission(); $submission->setDateSubmitted(new \DateTime()); $submission->setForm($form); $ipAddress = $this->ipLookupHelper->getIpAddress(); $submission->setIpAddress($ipAddress); if (!empty($post['return'])) { $referer = $post['return']; } elseif (!empty($server['HTTP_REFERER'])) { $referer = $server['HTTP_REFERER']; } else { $referer = ''; } //clean the referer by removing mauticError and mauticMessage $referer = InputHelper::url($referer, null, null, array('mauticError', 'mauticMessage')); $submission->setReferer($referer); $fields = $form->getFields(); $fieldArray = array(); $results = array(); $tokens = array(); $leadFieldMatches = array(); $validationErrors = array(); foreach ($fields as $f) { $id = $f->getId(); $type = $f->getType(); $alias = $f->getAlias(); $value = isset($post[$alias]) ? $post[$alias] : ''; $fieldArray[$id] = array('id' => $id, 'type' => $type, 'alias' => $alias); if (in_array($type, array('button', 'freetext'))) { //don't save items that don't have a value associated with it continue; } elseif ($type == 'captcha') { $captcha = $fieldHelper->validateFieldValue($type, $value, $f); if (!empty($captcha)) { $props = $f->getProperties(); //check for a custom message $validationErrors[$alias] = !empty($props['errorMessage']) ? $props['errorMessage'] : implode('<br />', $captcha); } continue; } if ($f->isRequired() && empty($value)) { //somehow the user got passed the JS validation $msg = $f->getValidationMessage(); if (empty($msg)) { $msg = $this->translator->trans('mautic.form.field.generic.validationfailed', array('%label%' => $f->getLabel()), 'validators'); } $validationErrors[$alias] = $msg; continue; } //clean and validate the input if ($f->isCustom()) { $params = $f->getCustomParameters(); if (!empty($value)) { if (isset($params['valueFilter'])) { if (is_string($params['inputFilter'] && method_exists('\\Mautic\\CoreBundle\\Helper\\InputHelper', $params['valueFilter']))) { $value = InputHelper::_($value, $params['valueFilter']); } elseif (is_callable($params['valueFilter'])) { $value = call_user_func_array($params['valueFilter'], array($f, $value)); } else { $value = InputHelper::_($value, 'clean'); } } else { $value = InputHelper::_($value, 'clean'); } } if (isset($params['valueConstraints']) && is_callable($params['valueConstraints'])) { $customErrors = call_user_func_array($params['valueConstraints'], array($f, $value)); if (!empty($customErrors)) { $validationErrors[$alias] = is_array($customErrors) ? implode('<br />', $customErrors) : $customErrors; } } } elseif (!empty($value)) { $filter = $fieldHelper->getFieldFilter($type); $value = InputHelper::_($value, $filter); $validation = $fieldHelper->validateFieldValue($type, $value); if (!empty($validation)) { $validationErrors[$alias] = is_array($validation) ? implode('<br />', $validation) : $validation; } } //convert array from checkbox groups and multiple selects if (is_array($value)) { $value = implode(", ", $value); } $tokens["{formfield={$alias}}"] = $value; //save the result if ($f->getSaveResult() !== false) { $results[$alias] = $value; } $leadField = $f->getLeadField(); if (!empty($leadField)) { $leadFieldMatches[$leadField] = $value; } } $submission->setResults($results); //execute submit actions $actions = $form->getActions(); //get post submit actions to make sure it still exists $components = $this->formModel->getCustomComponents(); $availableActions = $components['actions']; $args = array('post' => $post, 'server' => $server, 'factory' => $this->factory, 'submission' => $submission, 'fields' => $fieldArray, 'form' => $form, 'tokens' => $tokens); foreach ($actions as $action) { $key = $action->getType(); if (!isset($availableActions[$key])) { continue; } $settings = $availableActions[$key]; $args['action'] = $action; $args['config'] = $action->getProperties(); if (array_key_exists('validator', $settings)) { $callback = $settings['validator']; if (is_callable($callback)) { if (is_array($callback)) { $reflection = new \ReflectionMethod($callback[0], $callback[1]); } elseif (strpos($callback, '::') !== false) { $parts = explode('::', $callback); $reflection = new \ReflectionMethod($parts[0], $parts[1]); } else { $reflection = new \ReflectionMethod(null, $callback); } $pass = array(); foreach ($reflection->getParameters() as $param) { if (isset($args[$param->getName()])) { $pass[] = $args[$param->getName()]; } else { $pass[] = null; } } list($validated, $validatedMessage) = $reflection->invokeArgs($this, $pass); if (!$validated) { $validationErrors[$alias] = $validatedMessage; } } } } //return errors if (!empty($validationErrors)) { return array('errors' => $validationErrors); } //set the landing page the form was submitted from if applicable if (!empty($post['mauticpage'])) { $page = $this->pageModel->getEntity((int) $post['mauticpage']); if ($page != null) { $submission->setPage($page); } } // Add a feedback parameter $args['feedback'] = array(); // Create/update lead if (!empty($leadFieldMatches)) { $this->createLeadFromSubmit($form, $leadFieldMatches); } if ($form->isStandalone()) { // Now handle post submission actions foreach ($actions as $action) { $key = $action->getType(); if (!isset($availableActions[$key])) { continue; } $settings = $availableActions[$key]; $args['action'] = $action; $args['config'] = $action->getProperties(); // Set the lead each time in case an action updates it $args['lead'] = $this->leadModel->getCurrentLead(); $callback = $settings['callback']; if (is_callable($callback)) { if (is_array($callback)) { $reflection = new \ReflectionMethod($callback[0], $callback[1]); } elseif (strpos($callback, '::') !== false) { $parts = explode('::', $callback); $reflection = new \ReflectionMethod($parts[0], $parts[1]); } else { $reflection = new \ReflectionMethod(null, $callback); } $pass = array(); foreach ($reflection->getParameters() as $param) { if (isset($args[$param->getName()])) { $pass[] = $args[$param->getName()]; } else { $pass[] = null; } } $returned = $reflection->invokeArgs($this, $pass); $args['feedback'][$key] = $returned; } } } // Get updated lead with tracking ID if ($form->isInKioskMode()) { $lead = $this->leadModel->getCurrentLead(); } else { list($lead, $trackingId, $generated) = $this->leadModel->getCurrentLead(true); //set tracking ID for stats purposes to determine unique hits $submission->setTrackingId($trackingId); } $submission->setLead($lead); if (!$form->isStandalone()) { // Find and add the lead to the associated campaigns $campaigns = $this->campaignModel->getCampaignsByForm($form); if (!empty($campaigns)) { foreach ($campaigns as $campaign) { $this->campaignModel->addLead($campaign, $lead); } } } //save entity after the form submission events are fired in case a new lead is created $this->saveEntity($submission); if ($this->dispatcher->hasListeners(FormEvents::FORM_ON_SUBMIT)) { $event = new SubmissionEvent($submission, $post, $server); $this->dispatcher->dispatch(FormEvents::FORM_ON_SUBMIT, $event); } //last round of callback commands from the submit actions; first come first serve foreach ($args['feedback'] as $k => $data) { if (!empty($data['callback'])) { return array('callback' => $data); } } //made it to the end so return false that there was not an error return false; }