mautic / app /bundles /FormBundle /Controller /FieldController.php
chrisbryan17's picture
Upload folder using huggingface_hub
d2897cd verified
<?php
namespace Mautic\FormBundle\Controller;
use Doctrine\Persistence\ManagerRegistry;
use Mautic\CoreBundle\Controller\FormController as CommonFormController;
use Mautic\CoreBundle\Factory\MauticFactory;
use Mautic\CoreBundle\Factory\ModelFactory;
use Mautic\CoreBundle\Helper\CoreParametersHelper;
use Mautic\CoreBundle\Helper\UserHelper;
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
use Mautic\CoreBundle\Service\FlashBag;
use Mautic\CoreBundle\Translation\Translator;
use Mautic\FormBundle\Collector\AlreadyMappedFieldCollectorInterface;
use Mautic\FormBundle\Collector\MappedObjectCollectorInterface;
use Mautic\FormBundle\Entity\Field;
use Mautic\FormBundle\Event\FormBuilderEvent;
use Mautic\FormBundle\FormEvents;
use Mautic\FormBundle\Helper\FormFieldHelper;
use Mautic\FormBundle\Model\FieldModel;
use Mautic\FormBundle\Model\FormModel;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
class FieldController extends CommonFormController
{
public function __construct(
private FormModel $formModel,
private FieldModel $formFieldModel,
FormFieldHelper $fieldHelper,
FormFactoryInterface $formFactory,
private MappedObjectCollectorInterface $mappedObjectCollector,
private AlreadyMappedFieldCollectorInterface $alreadyMappedFieldCollector,
ManagerRegistry $doctrine,
MauticFactory $factory,
ModelFactory $modelFactory,
UserHelper $userHelper,
CoreParametersHelper $coreParametersHelper,
EventDispatcherInterface $dispatcher,
Translator $translator,
FlashBag $flashBag,
RequestStack $requestStack,
CorePermissions $security
) {
$this->fieldHelper = $fieldHelper;
$this->formFactory = $formFactory;
parent::__construct($formFactory, $fieldHelper, $doctrine, $factory, $modelFactory, $userHelper, $coreParametersHelper, $dispatcher, $translator, $flashBag, $requestStack, $security);
}
/**
* Generates new form and processes post data.
*
* @return Response
*/
public function newAction(Request $request)
{
$success = 0;
$valid = $cancelled = false;
$method = $request->getMethod();
$session = $request->getSession();
if ('POST' == $method) {
$formField = $request->request->all()['formfield'] ?? [];
$fieldType = $formField['type'];
$formId = $formField['formId'];
} else {
$fieldType = $request->query->get('type');
$formId = $request->query->get('formId');
$formField = [
'type' => $fieldType,
'formId' => $formId,
'parent' => $request->query->get('parent'),
];
}
$customComponents = $this->formModel->getCustomComponents();
$customParams = $customComponents['fields'][$fieldType] ?? false;
// ajax only for form fields
if (!$fieldType
|| !$request->isXmlHttpRequest()
|| !$this->security->isGranted(['form:forms:editown', 'form:forms:editother', 'form:forms:create'], 'MATCH_ONE')
) {
return $this->modalAccessDenied();
}
// Generate the form
$form = $this->getFieldForm($formId, $formField);
if (!empty($customParams)) {
$formField['isCustom'] = true;
$formField['customParameters'] = $customParams;
}
// Check for a submitted form and process it
if ('POST' == $method) {
if (!$cancelled = $this->isFormCancelled($form)) {
if ($valid = $this->isFormValid($form)) {
$success = 1;
// form is valid so process the data
$keyId = 'new'.hash('sha1', uniqid(mt_rand()));
// save the properties to session
$fields = $session->get('mautic.form.'.$formId.'.fields.modified', []);
$formData = $form->getData();
$formField = array_merge($formField, $formData);
$formField['id'] = $keyId;
// Get aliases in order to generate a new one for the new field
$aliases = [];
foreach ($fields as $f) {
$aliases[] = $f['alias'];
}
// Generate or ensure a unique alias
$alias = empty($formField['alias']) ? $formField['label'] : $formField['alias'];
$formFieldModel = $this->getModel('form.field');
\assert($formFieldModel instanceof FieldModel);
$formField['alias'] = $formFieldModel->generateAlias($alias, $aliases);
// Force required for captcha if not a honeypot
if ('captcha' == $formField['type']) {
$formField['isRequired'] = !empty($formField['properties']['captcha']);
}
// Add it to the next to last assuming the last is the submit button
if (count($fields)) {
$lastField = end($fields);
$lastKey = key($fields);
array_pop($fields);
$fields[$keyId] = $formField;
$fields[$lastKey] = $lastField;
} else {
$fields[$keyId] = $formField;
}
$session->set('mautic.form.'.$formId.'.fields.modified', $fields);
// Keep track of used lead fields
if (!empty($formField['mappedObject']) && !empty($formField['mappedField']) && empty($formData['parent'])) {
$this->alreadyMappedFieldCollector->addField($formId, $formField['mappedObject'], $formField['mappedField']);
}
} else {
$success = 0;
}
}
}
$viewParams = ['type' => $fieldType];
if ($cancelled || $valid) {
$closeModal = true;
} else {
$closeModal = false;
$viewParams['tmpl'] = 'field';
$viewParams['form'] = (isset($customParams['formTheme'])) ? $this->setFormTheme($form, '@MauticForm/Builder/field.html.twig', $customParams['formTheme']) : $form->createView();
$viewParams['fieldHeader'] = (!empty($customParams)) ? $this->translator->trans($customParams['label']) : $this->translator->transConditional('mautic.core.type.'.$fieldType, 'mautic.form.field.type.'.$fieldType);
}
$passthroughVars = [
'mauticContent' => 'formField',
'success' => $success,
'route' => false,
];
if (!empty($keyId)) {
$entity = new Field();
$blank = $entity->convertToArray();
$formField = array_merge($blank, $formField);
$formEntity = $this->formModel->getEntity($formId);
$passthroughVars['parent'] = $formField['parent'];
$passthroughVars['fieldId'] = $keyId;
$template = (!empty($customParams)) ? $customParams['template'] : '@MauticForm/Field/'.$fieldType.'.html.twig';
$leadFieldModel = $this->getModel('lead.field');
\assert($leadFieldModel instanceof \Mautic\LeadBundle\Model\FieldModel);
$passthroughVars['fieldHtml'] = $this->renderView(
'@MauticForm/Builder/_field_wrapper.html.twig',
[
'isConditional' => !empty($formField['parent']),
'template' => $template,
'inForm' => true,
'field' => $formField,
'id' => $keyId,
'formId' => $formId,
'formName' => null === $formEntity ? 'newform' : $formEntity->generateFormName(),
'mappedFields' => $this->mappedObjectCollector->buildCollection((string) $formField['mappedObject']),
'inBuilder' => true,
'fields' => $this->fieldHelper->getChoiceList($customComponents['fields']),
'viewOnlyFields' => $customComponents['viewOnlyFields'],
'formFields' => $fields,
]
);
}
if ($closeModal) {
// just close the modal
$passthroughVars['closeModal'] = 1;
return new JsonResponse($passthroughVars);
}
return $this->ajaxAction($request, [
'contentTemplate' => '@MauticForm/Builder/'.$viewParams['tmpl'].'.html.twig',
'viewParameters' => $viewParams,
'passthroughVars' => $passthroughVars,
]);
}
/**
* Generates edit form and processes post data.
*
* @param int $objectId
*
* @return Response
*/
public function editAction(Request $request, $objectId)
{
$session = $request->getSession();
$method = $request->getMethod();
$formfield = $request->request->get('formfield') ?? [];
$formId = 'POST' === $method ? ($formfield['formId'] ?? '') : $request->query->get('formId');
$fields = $session->get('mautic.form.'.$formId.'.fields.modified', []);
$success = 0;
$valid = $cancelled = false;
$formField = array_key_exists($objectId, $fields) ? $fields[$objectId] : [];
if ($formField) {
$fieldType = $formField['type'];
// ajax only for form fields
if (!$fieldType
|| !$request->isXmlHttpRequest()
|| !$this->security->isGranted(['form:forms:editown', 'form:forms:editother', 'form:forms:create'], 'MATCH_ONE')
) {
return $this->modalAccessDenied();
}
// Generate the form
$form = $this->getFieldForm($formId, $formField);
// Check for a submitted form and process it
if ('POST' == $method) {
if (!$cancelled = $this->isFormCancelled($form)) {
if ($valid = $this->isFormValid($form)) {
$success = 1;
// form is valid so process the data
// save the properties to session
$session = $request->getSession();
$fields = $session->get('mautic.form.'.$formId.'.fields.modified');
$formData = $form->getData();
// overwrite with updated data
$formField = array_merge($fields[$objectId], $formData);
if (str_contains((string) $objectId, 'new')) {
// Get aliases in order to generate update for this one
$aliases = [];
foreach ($fields as $k => $f) {
if ($k != $objectId) {
$aliases[] = $f['alias'];
}
}
$formField['alias'] = $this->formFieldModel->generateAlias(
$formField['alias'] ?? $formField['label'] ?? '',
$aliases
);
}
// Force required for captcha if not a honeypot
if ('captcha' == $formField['type']) {
$formField['isRequired'] = !empty($formField['properties']['captcha']);
}
$fields[$objectId] = $formField;
$session->set('mautic.form.'.$formId.'.fields.modified', $fields);
// Keep track of used lead fields
if (!empty($formField['mappedObject']) && !empty($formField['mappedField']) && empty($formData['parent'])) {
$this->alreadyMappedFieldCollector->addField($formId, $formField['mappedObject'], $formField['mappedField']);
}
}
}
}
$viewParams = ['type' => $fieldType];
$customComponents = $this->formModel->getCustomComponents();
$customParams = $customComponents['fields'][$fieldType] ?? false;
if ($cancelled || $valid) {
$closeModal = true;
} else {
$closeModal = false;
$viewParams['tmpl'] = 'field';
$viewParams['form'] = (isset($customParams['formTheme'])) ? $this->setFormTheme(
$form,
'@MauticForm/Builder/field.html.twig',
$customParams['formTheme']
) : $form->createView();
$viewParams['fieldHeader'] = (!empty($customParams))
? $this->translator->trans($customParams['label'])
: $this->translator->transConditional('mautic.core.type.'.$fieldType, 'mautic.form.field.type.'.$fieldType);
}
$passthroughVars = [
'mauticContent' => 'formField',
'success' => $success,
'route' => false,
];
$passthroughVars['fieldId'] = $objectId;
$template = (!empty($customParams)) ? $customParams['template'] : '@MauticForm/Field/'.$fieldType.'.html.twig';
// prevent undefined errors
$entity = new Field();
$blank = $entity->convertToArray();
$formField = array_merge($blank, $formField);
$leadFieldModel = $this->getModel('lead.field');
\assert($leadFieldModel instanceof \Mautic\LeadBundle\Model\FieldModel);
$passthroughVars['fieldHtml'] = $this->renderView(
'@MauticForm/Builder/_field_wrapper.html.twig',
[
'isConditional' => !empty($formField['parent']),
'template' => $template,
'inForm' => true,
'field' => $formField,
'id' => $objectId,
'formId' => $formId,
'mappedFields' => $this->mappedObjectCollector->buildCollection((string) $formField['mappedObject']),
'inBuilder' => true,
'fields' => $this->fieldHelper->getChoiceList($customComponents['fields']),
'formFields' => $fields,
'viewOnlyFields' => $customComponents['viewOnlyFields'],
]
);
if ($closeModal) {
// just close the modal
$passthroughVars['closeModal'] = 1;
return new JsonResponse($passthroughVars);
}
return $this->ajaxAction(
$request,
[
'contentTemplate' => '@MauticForm/Builder/'.$viewParams['tmpl'].'.html.twig',
'viewParameters' => $viewParams,
'passthroughVars' => $passthroughVars,
]
);
}
return new JsonResponse(['success' => 0]);
}
/**
* Deletes the entity.
*
* @param int $objectId
*
* @return JsonResponse
*/
public function deleteAction(Request $request, $objectId)
{
$session = $request->getSession();
$formId = $request->query->get('formId');
$fields = $session->get('mautic.form.'.$formId.'.fields.modified', []);
$delete = $session->get('mautic.form.'.$formId.'.fields.deleted', []);
// ajax only for form fields
if (!$request->isXmlHttpRequest()
|| !$this->security->isGranted(['form:forms:editown', 'form:forms:editother', 'form:forms:create'], 'MATCH_ONE')
) {
return $this->accessDenied();
}
$formField = (array_key_exists($objectId, $fields)) ? $fields[$objectId] : null;
if ('POST' === $request->getMethod() && null !== $formField) {
if ($formField['mappedObject'] && $formField['mappedField']) {
// Allow to select the lead field from the delete field again
$this->alreadyMappedFieldCollector->removeField($formId, $formField['mappedObject'], $formField['mappedField']);
}
// add the field to the delete list
if (!in_array($objectId, $delete)) {
$delete[] = $objectId;
$session->set('mautic.form.'.$formId.'.fields.deleted', $delete);
}
$dataArray = [
'mauticContent' => 'formField',
'success' => 1,
'route' => false,
];
} else {
$dataArray = ['success' => 0];
}
return new JsonResponse($dataArray);
}
/**
* @param int $formId
* @param mixed[] $formField
*
* @return mixed
*/
private function getFieldForm($formId, array $formField)
{
// fire the form builder event
$formModel = $this->getModel('form.form');
\assert($formModel instanceof FormModel);
$customComponents = $this->formModel->getCustomComponents();
$customParams = $customComponents['fields'][$formField['type']] ?? false;
$formFieldModel = $this->getModel('form.field');
\assert($formFieldModel instanceof FieldModel);
$form = $formFieldModel->createForm(
$formField,
$this->formFactory,
(!empty($formField['id'])) ?
$this->generateUrl('mautic_formfield_action', ['objectAction' => 'edit', 'objectId' => $formField['id']])
: $this->generateUrl('mautic_formfield_action', ['objectAction' => 'new']),
['customParameters' => $customParams]
);
$form->get('formId')->setData($formId);
$event = new FormBuilderEvent($this->translator);
$this->dispatcher->dispatch($event, FormEvents::FORM_ON_BUILD);
$event->addValidatorsToBuilder($form);
return $form;
}
}