chrisbryan17's picture
Upload folder using huggingface_hub
d2897cd verified
raw
history blame contribute delete
36 kB
<?php
namespace Mautic\FormBundle\Model;
use Doctrine\ORM\EntityManagerInterface;
use Mautic\CoreBundle\Doctrine\Helper\ColumnSchemaHelper;
use Mautic\CoreBundle\Doctrine\Helper\TableSchemaHelper;
use Mautic\CoreBundle\Helper\Chart\ChartQuery;
use Mautic\CoreBundle\Helper\CoreParametersHelper;
use Mautic\CoreBundle\Helper\ThemeHelperInterface;
use Mautic\CoreBundle\Helper\UserHelper;
use Mautic\CoreBundle\Model\FormModel as CommonFormModel;
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
use Mautic\CoreBundle\Translation\Translator;
use Mautic\FormBundle\Collector\MappedObjectCollectorInterface;
use Mautic\FormBundle\Entity\Action;
use Mautic\FormBundle\Entity\Field;
use Mautic\FormBundle\Entity\Form;
use Mautic\FormBundle\Entity\FormRepository;
use Mautic\FormBundle\Event\FormBuilderEvent;
use Mautic\FormBundle\Event\FormEvent;
use Mautic\FormBundle\Form\Type\FormType;
use Mautic\FormBundle\FormEvents;
use Mautic\FormBundle\Helper\FormFieldHelper;
use Mautic\FormBundle\Helper\FormUploader;
use Mautic\FormBundle\ProgressiveProfiling\DisplayManager;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Helper\FormFieldHelper as ContactFieldHelper;
use Mautic\LeadBundle\Helper\PrimaryCompanyHelper;
use Mautic\LeadBundle\Model\FieldModel as LeadFieldModel;
use Mautic\LeadBundle\Tracker\ContactTracker;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\EventDispatcher\Event;
use Twig\Environment;
/**
* @extends CommonFormModel<Form>
*/
class FormModel extends CommonFormModel
{
public function __construct(
protected RequestStack $requestStack,
protected Environment $twig,
protected ThemeHelperInterface $themeHelper,
protected ActionModel $formActionModel,
protected FieldModel $formFieldModel,
protected FormFieldHelper $fieldHelper,
private PrimaryCompanyHelper $primaryCompanyHelper,
protected LeadFieldModel $leadFieldModel,
private FormUploader $formUploader,
private ContactTracker $contactTracker,
private ColumnSchemaHelper $columnSchemaHelper,
private TableSchemaHelper $tableSchemaHelper,
private MappedObjectCollectorInterface $mappedObjectCollector,
EntityManagerInterface $em,
CorePermissions $security,
EventDispatcherInterface $dispatcher,
UrlGeneratorInterface $router,
Translator $translator,
UserHelper $userHelper,
LoggerInterface $mauticLogger,
CoreParametersHelper $coreParametersHelper
) {
parent::__construct($em, $security, $dispatcher, $router, $translator, $userHelper, $mauticLogger, $coreParametersHelper);
}
/**
* @return FormRepository
*/
public function getRepository()
{
return $this->em->getRepository(Form::class);
}
public function getPermissionBase(): string
{
return 'form:forms';
}
public function getNameGetter(): string
{
return 'getName';
}
public function createForm($entity, FormFactoryInterface $formFactory, $action = null, $options = []): \Symfony\Component\Form\FormInterface
{
if (!$entity instanceof Form) {
throw new MethodNotAllowedHttpException(['Form']);
}
if (!empty($action)) {
$options['action'] = $action;
}
return $formFactory->create(FormType::class, $entity, $options);
}
/**
* @param string|int|null $id
*/
public function getEntity($id = null): ?Form
{
if (null === $id) {
return new Form();
}
$entity = parent::getEntity($id);
if ($entity && $entity->getFields()) {
foreach ($entity->getFields() as $field) {
$this->addMappedFieldOptions($field);
}
}
return $entity;
}
/**
* @throws MethodNotAllowedHttpException
*/
protected function dispatchEvent($action, &$entity, $isNew = false, Event $event = null): ?Event
{
if (!$entity instanceof Form) {
throw new MethodNotAllowedHttpException(['Form']);
}
switch ($action) {
case 'pre_save':
$name = FormEvents::FORM_PRE_SAVE;
break;
case 'post_save':
$name = FormEvents::FORM_POST_SAVE;
break;
case 'pre_delete':
$name = FormEvents::FORM_PRE_DELETE;
break;
case 'post_delete':
$name = FormEvents::FORM_POST_DELETE;
break;
default:
return null;
}
if ($this->dispatcher->hasListeners($name)) {
if (empty($event)) {
$event = new FormEvent($entity, $isNew);
$event->setEntityManager($this->em);
}
$this->dispatcher->dispatch($event, $name);
return $event;
} else {
return null;
}
}
public function setFields(Form $entity, $sessionFields): void
{
$order = 1;
$existingFields = $entity->getFields()->toArray();
$formName = $entity->generateFormName();
foreach ($sessionFields as $key => $properties) {
$isNew = (!empty($properties['id']) && isset($existingFields[$properties['id']])) ? false : true;
$field = !$isNew ? $existingFields[$properties['id']] : new Field();
if (!$isNew) {
if (empty($properties['alias'])) {
$properties['alias'] = $field->getAlias();
}
if (empty($properties['label'])) {
$properties['label'] = $field->getLabel();
}
}
if ($formName === $properties['alias']) {
// Change the alias to prevent potential ID collisions in the rendered HTML
$properties['alias'] = 'f_'.$properties['alias'];
}
foreach ($properties as $f => $v) {
if (in_array($f, ['id', 'order'])) {
continue;
}
$func = 'set'.ucfirst($f);
if (method_exists($field, $func)) {
$field->$func($v);
}
}
$field->setForm($entity);
$field->setSessionId($key);
if (!$field->getParent()) {
$field->setOrder($order);
++$order;
} else {
if (isset($sessionFields[$field->getParent()]['order'])) {
$field->setOrder($sessionFields[$field->getParent()]['order']);
} else {
$field->setOrder($order);
}
}
$entity->addField($properties['id'], $field);
}
// Persist if the entity is known
if ($entity->getId()) {
$this->formFieldModel->saveEntities($existingFields);
}
}
public function deleteFields(Form $entity, $sessionFields): void
{
if (empty($sessionFields)) {
return;
}
$existingFields = $entity->getFields()->toArray();
$deleteFields = [];
foreach ($sessionFields as $fieldId) {
if (!isset($existingFields[$fieldId])) {
continue;
}
$this->handleFilesDelete($existingFields[$fieldId]);
$entity->removeField($fieldId, $existingFields[$fieldId]);
$deleteFields[] = $fieldId;
}
// Delete fields from db
if (count($deleteFields)) {
$this->formFieldModel->deleteEntities($deleteFields);
}
}
private function handleFilesDelete(Field $field): void
{
if (!$field->isFileType()) {
return;
}
$this->formUploader->deleteAllFilesOfFormField($field);
}
public function setActions(Form $entity, $sessionActions): void
{
$order = 1;
$existingActions = $entity->getActions()->toArray();
$savedFields = $entity->getFields()->toArray();
// match sessionId with field Id to update mapped fields
$fieldIds = [];
foreach ($savedFields as $field) {
$fieldIds[$field->getSessionId()] = $field->getId();
}
foreach ($sessionActions as $properties) {
$isNew = (!empty($properties['id']) && isset($existingActions[$properties['id']])) ? false : true;
$action = !$isNew ? $existingActions[$properties['id']] : new Action();
foreach ($properties as $f => $v) {
if (in_array($f, ['id', 'order'])) {
continue;
}
$func = 'set'.ucfirst($f);
if ('properties' == $f) {
if (isset($v['mappedFields'])) {
foreach ($v['mappedFields'] as $pk => $pv) {
if (str_contains($pv, 'new')) {
$v['mappedFields'][$pk] = $fieldIds[$pv];
}
}
}
}
if (method_exists($action, $func)) {
$action->$func($v);
}
}
$action->setForm($entity);
$action->setOrder($order);
++$order;
$entity->addAction($properties['id'], $action);
}
// Persist if form is being edited
if ($entity->getId()) {
$this->formActionModel->saveEntities($existingActions);
}
}
/**
* @param array $actions
*/
public function deleteActions(Form $entity, $actions): void
{
if (empty($actions)) {
return;
}
$existingActions = $entity->getActions()->toArray();
$deleteActions = [];
foreach ($actions as $actionId) {
if (isset($existingActions[$actionId])) {
$actionEntity = $this->em->getReference(Action::class, (int) $actionId);
$entity->removeAction($actionEntity);
$deleteActions[] = $actionId;
}
}
// Delete actions from db
if (count($deleteActions)) {
$this->formActionModel->deleteEntities($deleteActions);
}
}
public function saveEntity($entity, $unlock = true): void
{
$isNew = ($entity->getId()) ? false : true;
if ($isNew && !$entity->getAlias()) {
$alias = $this->cleanAlias($entity->getName(), '', 10);
$entity->setAlias($alias);
}
$this->backfillReplacedPropertiesForBc($entity);
// save the form so that the ID is available for the form html
parent::saveEntity($entity, $unlock);
// now build the form table
if ($entity->getId()) {
$this->createTableSchema($entity, $isNew);
}
$this->generateHtml($entity);
}
/**
* Obtains the content.
*
* @param bool|true $withScript
* @param bool|true $useCache
*/
public function getContent(Form $form, $withScript = true, $useCache = true): string
{
$html = $this->getFormHtml($form, $useCache);
if ($withScript) {
$html = $this->getFormScript($form)."\n\n".$this->removeScriptTag($html);
} else {
$html = $this->removeScriptTag($html);
}
return $html;
}
/**
* Obtains the cached HTML of a form and generates it if missing.
*
* @param bool|true $useCache
*
* @return string
*/
public function getFormHtml(Form $form, $useCache = true)
{
if ($useCache && !$form->usesProgressiveProfiling()) {
$cachedHtml = $form->getCachedHtml();
}
if (empty($cachedHtml)) {
$cachedHtml = $this->generateHtml($form, $useCache);
}
if (!$form->getInKioskMode()) {
$this->populateValuesWithLead($form, $cachedHtml);
}
return $cachedHtml;
}
/**
* Get results for a form and lead.
*
* @param int $leadId
* @param int $limit
*/
public function getLeadSubmissions(Form $form, $leadId, $limit = 200): array
{
return $this->getRepository()->getFormResults(
$form,
[
'leadId' => $leadId,
'limit' => $limit,
]
);
}
/**
* Generate the form's html.
*
* @param bool $persist
*/
public function generateHtml(Form $entity, $persist = true): string
{
// Use specific template or system-wide default theme
$theme = $entity->getTemplate() ?? $this->coreParametersHelper->get('theme');
$submissions = null;
$lead = ($this->requestStack->getCurrentRequest()) ? $this->contactTracker->getContact() : null;
$style = '';
$styleToRender = '@MauticForm/Builder/_style.html.twig';
$formToRender = '@MauticForm/Builder/form.html.twig';
if ($this->twig->getLoader()->exists('@themes/'.$theme.'/html/MauticFormBundle/Builder/_style.html.twig')) {
$styleToRender = '@themes/'.$theme.'/html/MauticFormBundle/Builder/_style.html.twig';
}
if ($this->twig->getLoader()->exists('@themes/'.$theme.'/html/MauticFormBundle/Builder/form.html.twig')) {
$formToRender = '@themes/'.$theme.'/html/MauticFormBundle/Builder/form.html.twig';
}
if ($lead instanceof Lead && $lead->getId() && $entity->usesProgressiveProfiling()) {
$submissions = $this->getLeadSubmissions($entity, $lead->getId());
}
if ($entity->getRenderStyle()) {
$styleTheme = $styleToRender;
$style = $this->twig->render($this->themeHelper->checkForTwigTemplate($styleTheme));
}
// Determine pages
$fields = $entity->getFields()->toArray();
// Ensure the correct order in case this is generated right after a form save with new fields
uasort($fields, fn ($a, $b): int => $a->getOrder() <=> $b->getOrder());
$viewOnlyFields = $this->getCustomComponents()['viewOnlyFields'];
$displayManager = new DisplayManager($entity, !empty($viewOnlyFields) ? $viewOnlyFields : []);
[$pages, $lastPage] = $this->getPages($fields);
$html = $this->twig->render(
$formToRender,
[
'fieldSettings' => $this->getCustomComponents()['fields'],
'viewOnlyFields' => $viewOnlyFields,
'fields' => $fields,
'mappedFields' => $this->mappedObjectCollector->buildCollection(...$entity->getMappedFieldObjects()),
'form' => $entity,
'theme' => '@themes/'.$entity->getTemplate().'/Field/',
'submissions' => $submissions,
'lead' => $lead,
'formPages' => $pages,
'lastFormPage' => $lastPage,
'style' => $style,
'inBuilder' => false,
'displayManager' => $displayManager,
'successfulSubmitAction' => $this->coreParametersHelper->get('successful_submit_action'),
]
);
if (!$entity->usesProgressiveProfiling()) {
$entity->setCachedHtml($html);
if ($persist) {
// bypass model function as events aren't needed for this
$this->getRepository()->saveEntity($entity);
}
}
return $html;
}
public function getPages(array $fields): array
{
$pages = ['open' => [], 'close' => []];
$openFieldId =
$previousId =
$lastPage = false;
$pageCount = 1;
foreach ($fields as $fieldId => $field) {
if ('pagebreak' == $field->getType() && $openFieldId) {
// Open the page
$pages['open'][$openFieldId] = $pageCount;
$openFieldId = false;
$lastPage = $fieldId;
// Close the page at the next page break
if ($previousId) {
$pages['close'][$previousId] = $pageCount;
++$pageCount;
}
} else {
if (!$openFieldId) {
$openFieldId = $fieldId;
}
}
$previousId = $fieldId;
}
if ($openFieldId) {
$pages['open'][$openFieldId] = $pageCount;
}
if ($previousId !== $lastPage) {
$pages['close'][$previousId] = $pageCount;
}
return [$pages, $lastPage];
}
/**
* Creates the table structure for form results.
*
* @param bool $isNew
* @param bool $dropExisting
*/
public function createTableSchema(Form $entity, $isNew = false, $dropExisting = false): void
{
// create the field as its own column in the leads table
$name = 'form_results_'.$entity->getId().'_'.$entity->getAlias();
$columns = $this->generateFieldColumns($entity);
if ($isNew || (!$isNew && !$this->tableSchemaHelper->checkTableExists($name))) {
$this->tableSchemaHelper->addTable([
'name' => $name,
'columns' => $columns,
'options' => [
'primaryKey' => ['submission_id'],
'uniqueIndex' => ['submission_id', 'form_id'],
],
], true, $dropExisting);
$this->tableSchemaHelper->executeChanges();
} else {
// check to make sure columns exist
$columnSchemaHelper = $this->columnSchemaHelper->setName($name);
foreach ($columns as $c) {
if (!$columnSchemaHelper->checkColumnExists($c['name'])) {
$columnSchemaHelper->addColumn($c, false);
}
}
$columnSchemaHelper->executeChanges();
}
}
public function deleteEntity($entity): void
{
/* @var Form $entity */
$this->deleteFormFiles($entity);
if (!$entity->getId()) {
// delete the associated results table
$this->tableSchemaHelper->deleteTable('form_results_'.$entity->deletedId.'_'.$entity->getAlias());
$this->tableSchemaHelper->executeChanges();
}
parent::deleteEntity($entity);
}
/**
* @param mixed[] $ids
*
* @return mixed[]
*/
public function deleteEntities($ids): array
{
$entities = parent::deleteEntities($ids);
foreach ($entities as $id => $entity) {
/* @var Form $entity */
// delete the associated results table
$this->tableSchemaHelper->deleteTable('form_results_'.$id.'_'.$entity->getAlias());
$this->deleteFormFiles($entity);
}
$this->tableSchemaHelper->executeChanges();
return $entities;
}
private function deleteFormFiles(Form $form): void
{
$this->formUploader->deleteFilesOfForm($form);
}
/**
* Generate an array of columns from fields.
*/
public function generateFieldColumns(Form $form): array
{
$fields = $form->getFields()->toArray();
$columns = [
[
'name' => 'submission_id',
'type' => 'integer',
],
[
'name' => 'form_id',
'type' => 'integer',
],
];
$ignoreTypes = $this->getCustomComponents()['viewOnlyFields'];
foreach ($fields as $f) {
if (!in_array($f->getType(), $ignoreTypes)) {
$columns[] = [
'name' => $f->getAlias(),
'type' => 'text',
'options' => [
'notnull' => false,
],
];
}
}
return $columns;
}
/**
* Gets array of custom fields and submit actions from bundles subscribed FormEvents::FORM_ON_BUILD.
*
* @return mixed
*/
public function getCustomComponents()
{
static $customComponents;
if (empty($customComponents)) {
// build them
$event = new FormBuilderEvent($this->translator);
$this->dispatcher->dispatch($event, FormEvents::FORM_ON_BUILD);
$customComponents['fields'] = $event->getFormFields();
$customComponents['actions'] = $event->getSubmitActions();
$customComponents['choices'] = $event->getSubmitActionGroups();
$customComponents['validators'] = $event->getValidators();
// Generate a list of fields that are not persisted to the database by default
$notPersist = ['button', 'captcha', 'freetext', 'freehtml', 'pagebreak'];
foreach ($customComponents['fields'] as $type => $field) {
if (isset($field['builderOptions']) && isset($field['builderOptions']['addSaveResult']) && false === $field['builderOptions']['addSaveResult']) {
$notPersist[] = $type;
}
}
$customComponents['viewOnlyFields'] = $notPersist;
}
return $customComponents;
}
/**
* Get the document write javascript for the form.
*/
public function getAutomaticJavascript(Form $form): string
{
$html = $this->getContent($form, false);
$formScript = $this->getFormScript($form);
// replace line breaks with literal symbol and escape quotations
$search = ["\r\n", "\n", '"'];
$replace = ['', '', '\"'];
$html = str_replace($search, $replace, $html);
$oldFormScript = str_replace($search, $replace, $formScript);
$newFormScript = $this->generateJsScript($formScript);
// Write html for all browser and fallback for IE
$script = '
var scr = document.currentScript;
var html = "'.$html.'";
if (scr !== undefined) {
scr.insertAdjacentHTML("afterend", html);
'.$newFormScript.'
} else {
document.write("'.$oldFormScript.'"+html);
}
';
return $script;
}
public function getFormScript(Form $form): string
{
$theme = $form->getTemplate();
$scriptToRender = '@MauticForm/Builder/_script.html.twig';
if (!empty($theme)) {
if ($this->twig->getLoader()->exists('@themes/'.$theme.'/MauticForm/Builder/_script.html.twig')) {
$scriptToRender = '@themes/'.$theme.'/MauticForm/Builder/_script.html.twig';
}
}
$script = $this->twig->render(
$scriptToRender,
[
'form' => $form,
'theme' => $theme,
]
);
$html = $this->getFormHtml($form);
$scripts = $this->extractScriptTag($html);
foreach ($scripts as $item) {
$script .= $item."\n";
}
return $script;
}
/**
* Writes in form values from get parameters.
*/
public function populateValuesWithGetParameters(Form $form, &$formHtml): void
{
$formName = $form->generateFormName();
$request = $this->requestStack->getCurrentRequest();
$fields = $form->getFields()->toArray();
/** @var Field $f */
foreach ($fields as $f) {
$alias = $f->getAlias();
if ($request->query->has($alias)) {
$value = urlencode($request->query->get($alias));
$this->fieldHelper->populateField($f, $value, $formName, $formHtml);
}
}
}
/**
* @param string $formHtml
*/
public function populateValuesWithLead(Form $form, &$formHtml): void
{
$formName = $form->generateFormName();
$fields = $form->getFields();
$autoFillFields = [];
$objectsToAutoFill = ['contact', 'company'];
/** @var Field $field */
foreach ($fields as $key => $field) {
// we want work just with matched autofill fields
if (
$field->getMappedField()
&& $field->getIsAutoFill()
&& in_array($field->getMappedObject(), $objectsToAutoFill)
) {
$autoFillFields[$key] = $field;
}
}
// no fields for populate
if (!count($autoFillFields)) {
return;
}
$lead = $this->contactTracker->getContact();
if (!$lead instanceof Lead) {
return;
}
// get the contact (lead) and primary company field values
$leadArray = $this->primaryCompanyHelper->getProfileFieldsWithPrimaryCompany($lead);
if (!is_array($leadArray) || count($leadArray) <= 0) {
return;
}
foreach ($autoFillFields as $field) {
$value = $leadArray[$field->getMappedField()] ?? '';
// just skip string empty field
if ('' !== $value) {
$this->fieldHelper->populateField($field, $value, $formName, $formHtml);
}
}
}
public function getFilterExpressionFunctions($operator = null): array
{
$operatorOptions = [
'=' => [
'label' => 'mautic.lead.list.form.operator.equals',
'expr' => 'eq',
'negate_expr' => 'neq',
],
'!=' => [
'label' => 'mautic.lead.list.form.operator.notequals',
'expr' => 'neq',
'negate_expr' => 'eq',
],
'gt' => [
'label' => 'mautic.lead.list.form.operator.greaterthan',
'expr' => 'gt',
'negate_expr' => 'lt',
],
'gte' => [
'label' => 'mautic.lead.list.form.operator.greaterthanequals',
'expr' => 'gte',
'negate_expr' => 'lt',
],
'lt' => [
'label' => 'mautic.lead.list.form.operator.lessthan',
'expr' => 'lt',
'negate_expr' => 'gt',
],
'lte' => [
'label' => 'mautic.lead.list.form.operator.lessthanequals',
'expr' => 'lte',
'negate_expr' => 'gt',
],
'like' => [
'label' => 'mautic.lead.list.form.operator.islike',
'expr' => 'like',
'negate_expr' => 'notLike',
],
'!like' => [
'label' => 'mautic.lead.list.form.operator.isnotlike',
'expr' => 'notLike',
'negate_expr' => 'like',
],
'startsWith' => [
'label' => 'mautic.core.operator.starts.with',
'expr' => 'startsWith',
'negate_expr' => 'startsWith',
],
'endsWith' => [
'label' => 'mautic.core.operator.ends.with',
'expr' => 'endsWith',
'negate_expr' => 'endsWith',
],
'contains' => [
'label' => 'mautic.core.operator.contains',
'expr' => 'contains',
'negate_expr' => 'contains',
],
];
return (null === $operator) ? $operatorOptions : $operatorOptions[$operator];
}
/**
* Get a list of assets in a date range.
*
* @param int $limit
* @param array $filters
* @param array $options
*
* @return array
*/
public function getFormList($limit = 10, \DateTime $dateFrom = null, \DateTime $dateTo = null, $filters = [], $options = [])
{
$q = $this->em->getConnection()->createQueryBuilder();
$q->select('t.id, t.name, t.date_added, t.date_modified')
->from(MAUTIC_TABLE_PREFIX.'forms', 't')
->setMaxResults($limit);
if (!empty($options['canViewOthers'])) {
$q->andWhere('t.created_by = :userId')
->setParameter('userId', $this->userHelper->getUser()->getId());
}
$chartQuery = new ChartQuery($this->em->getConnection(), $dateFrom, $dateTo);
$chartQuery->applyFilters($q, $filters);
$chartQuery->applyDateFilters($q, 'date_added');
return $q->execute()->fetchAllAssociative();
}
/**
* Load HTML consider Libxml < 2.7.8.
*/
private function loadHTML(&$dom, $html): void
{
if (defined('LIBXML_HTML_NOIMPLIED') && defined('LIBXML_HTML_NODEFDTD')) {
$dom->loadHTML(mb_encode_numericentity($html, [0x80, 0x10FFFF, 0, 0xFFFFF], 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
} else {
$dom->loadHTML(mb_encode_numericentity($html, [0x80, 0x10FFFF, 0, 0xFFFFF], 'UTF-8'));
}
}
/**
* Save HTML consider Libxml < 2.7.8.
*
* @return string
*/
private function saveHTML($dom, $html)
{
if (defined('LIBXML_HTML_NOIMPLIED') && defined('LIBXML_HTML_NODEFDTD')) {
return $dom->saveHTML($html);
} else {
// remove DOCTYPE, <html>, and <body> tags for old libxml
return preg_replace('/^<!DOCTYPE.+?>/', '', str_replace(['<html>', '</html>', '<body>', '</body>'], ['', '', '', ''], $dom->saveHTML($html)));
}
}
/**
* Extract script from html.
*/
private function extractScriptTag($html): array
{
libxml_use_internal_errors(true);
$dom = new \DOMDocument();
$this->loadHTML($dom, $html);
$items = $dom->getElementsByTagName('script');
$scripts = [];
foreach ($items as $script) {
$scripts[] = $this->saveHTML($dom, $script);
}
return $scripts;
}
/**
* Remove script from html.
*/
private function removeScriptTag($html): string
{
libxml_use_internal_errors(true);
$dom = new \DOMDocument();
$this->loadHTML($dom, '<div>'.$html.'</div>');
$items = $dom->getElementsByTagName('script');
$remove = [];
foreach ($items as $item) {
$remove[] = $item;
}
foreach ($remove as $item) {
$item->parentNode->removeChild($item);
}
$root = $dom->documentElement;
$result = '';
foreach ($root->childNodes as $childNode) {
$result .= $this->saveHTML($dom, $childNode);
}
return $result;
}
/**
* Generate dom manipulation javascript to include all script.
*/
private function generateJsScript($html): string
{
libxml_use_internal_errors(true);
$dom = new \DOMDocument();
$this->loadHTML($dom, '<div>'.$html.'</div>');
$items = $dom->getElementsByTagName('script');
$javascript = '';
foreach ($items as $key => $script) {
if ($script->hasAttribute('src')) {
$javascript .= "
var script$key = document.createElement('script');
script$key.src = '".$script->getAttribute('src')."';
document.getElementsByTagName('head')[0].appendChild(script$key);";
} else {
$scriptContent = $script->nodeValue;
$scriptContent = str_replace(["\r\n", "\n", '"'], ['', '', '\"'], $scriptContent);
$javascript .= "
var inlineScript$key = document.createTextNode(\"$scriptContent\");
var script$key = document.createElement('script');
script$key.appendChild(inlineScript$key);
document.getElementsByTagName('head')[0].appendChild(script$key);";
}
}
return $javascript;
}
/**
* Finds out whether the.
*/
private function addMappedFieldOptions(Field $formField): void
{
$formFieldProps = $formField->getProperties();
$mappedFieldAlias = $formField->getMappedField();
if (empty($formFieldProps['syncList']) || empty($mappedFieldAlias) || 'contact' !== $formField->getMappedObject()) {
return;
}
$list = $this->getContactFieldPropertiesList($mappedFieldAlias);
if (!empty($list)) {
$formFieldProps['list'] = ['list' => $list];
if (array_key_exists('optionlist', $formFieldProps)) {
$formFieldProps['optionlist'] = ['list' => $list];
}
$formField->setProperties($formFieldProps);
}
}
/**
* @return mixed[]|null
*/
public function getContactFieldPropertiesList(string $contactFieldAlias): ?array
{
$contactField = $this->leadFieldModel->getEntityByAlias($contactFieldAlias); // @todo this must use all objects as well. Not just contact.
if (empty($contactField) || !in_array($contactField->getType(), ContactFieldHelper::getListTypes())) {
return null;
}
$contactFieldProps = $contactField->getProperties();
switch ($contactField->getType()) {
case 'select':
case 'multiselect':
case 'lookup':
$list = $contactFieldProps['list'] ?? [];
break;
case 'boolean':
$list = [$contactFieldProps['no'], $contactFieldProps['yes']];
break;
case 'country':
$list = ContactFieldHelper::getCountryChoices();
break;
case 'region':
$list = ContactFieldHelper::getRegionChoices();
break;
case 'timezone':
$list = ContactFieldHelper::getTimezonesChoices();
break;
case 'locale':
$list = ContactFieldHelper::getLocaleChoices();
break;
default:
return null;
}
return $list;
}
/**
* @param string $fieldAlias
*
* @return Field|null
*/
public function findFormFieldByAlias(Form $form, $fieldAlias)
{
foreach ($form->getFields() as $field) {
if ($field->getAlias() === $fieldAlias) {
return $field;
}
}
return null;
}
private function backfillReplacedPropertiesForBc(Form $entity): void
{
/** @var Field $field */
foreach ($entity->getFields() as $field) {
if (!$field->getLeadField() && $field->getMappedField()) {
$field->setLeadField($field->getMappedField());
} elseif ($field->getLeadField() && !$field->getMappedField()) {
$field->setMappedField($field->getLeadField());
$field->setMappedObject(
str_starts_with($field->getLeadField(), 'company') && 'company' !== $field->getLeadField() ? 'company' : 'contact'
);
}
}
}
}