Spaces:
No application file
No application file
namespace Mautic\CampaignBundle\Controller; | |
use Doctrine\Persistence\ManagerRegistry; | |
use Mautic\CampaignBundle\Entity\Event; | |
use Mautic\CampaignBundle\EventCollector\EventCollector; | |
use Mautic\CampaignBundle\Form\Type\EventType; | |
use Mautic\CampaignBundle\Model\CampaignModel; | |
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\CoreBundle\Twig\Helper\DateHelper; | |
use Mautic\FormBundle\Helper\FormFieldHelper; | |
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; | |
class EventController extends CommonFormController | |
{ | |
/** | |
* @var string[] | |
*/ | |
private array $supportedEventTypes = [ | |
Event::TYPE_DECISION, | |
Event::TYPE_ACTION, | |
Event::TYPE_CONDITION, | |
]; | |
public function __construct( | |
FormFactoryInterface $formFactory, | |
FormFieldHelper $fieldHelper, | |
private EventCollector $eventCollector, | |
private DateHelper $dateHelper, | |
ManagerRegistry $doctrine, | |
MauticFactory $factory, | |
ModelFactory $modelFactory, | |
UserHelper $userHelper, | |
CoreParametersHelper $coreParametersHelper, | |
EventDispatcherInterface $dispatcher, | |
Translator $translator, | |
FlashBag $flashBag, | |
RequestStack $requestStack, | |
CorePermissions $security, | |
private CampaignModel $campaignModel | |
) { | |
parent::__construct($formFactory, $fieldHelper, $doctrine, $factory, $modelFactory, $userHelper, $coreParametersHelper, $dispatcher, $translator, $flashBag, $requestStack, $security); | |
} | |
/** | |
* Generates new form and processes post data. | |
* | |
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response | |
*/ | |
public function newAction(Request $request) | |
{ | |
$success = 0; | |
$valid = $cancelled = false; | |
$method = $request->getMethod(); | |
$session = $request->getSession(); | |
if ('POST' == $method) { | |
$event = $request->request->all()['campaignevent'] ?? []; | |
$type = $event['type']; | |
$eventType = $event['eventType']; | |
$campaignId = $event['campaignId']; | |
$event['triggerDate'] = (!empty($event['triggerDate'])) ? $this->factory->getDate($event['triggerDate'])->getDateTime() : null; | |
} else { | |
$type = $request->query->get('type'); | |
$eventType = $request->query->get('eventType'); | |
$campaignId = $request->query->get('campaignId'); | |
$anchorName = $request->query->get('anchor', ''); | |
$event = [ | |
'type' => $type, | |
'eventType' => $eventType, | |
'campaignId' => $campaignId, | |
'anchor' => $anchorName, | |
'anchorEventType' => $request->query->get('anchorEventType', ''), | |
]; | |
} | |
// set the eventType key for events | |
if (!in_array($eventType, $this->supportedEventTypes)) { | |
return $this->modalAccessDenied(); | |
} | |
// ajax only for form fields | |
if (!$type | |
|| !$request->isXmlHttpRequest() | |
|| !$this->security->isGranted( | |
[ | |
'campaign:campaigns:edit', | |
'campaign:campaigns:create', | |
], | |
'MATCH_ONE' | |
) | |
) { | |
return $this->modalAccessDenied(); | |
} | |
// fire the builder event | |
$events = $this->eventCollector->getEventsArray(); | |
$form = $this->formFactory->create( | |
EventType::class, | |
$event, | |
[ | |
'action' => $this->generateUrl('mautic_campaignevent_action', ['objectAction' => 'new']), | |
'settings' => $events[$eventType][$type], | |
] | |
); | |
$event['settings'] = $events[$eventType][$type]; | |
$form->get('campaignId')->setData($campaignId); | |
// 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((string) mt_rand())); | |
// save the properties to session | |
$modifiedEvents = $session->get('mautic.campaign.'.$campaignId.'.events.modified'); | |
$formData = $form->getData(); | |
$event = array_merge($event, $formData); | |
$event['id'] = $event['tempId'] = $keyId; | |
if (empty($event['name'])) { | |
// set it to the event default | |
$event['name'] = $this->translator->trans($event['settings']['label']); | |
} | |
$modifiedEvents[$keyId] = $event; | |
$session->set('mautic.campaign.'.$campaignId.'.events.modified', $modifiedEvents); | |
} else { | |
$success = 0; | |
} | |
} | |
} | |
$viewParams = ['type' => $type]; | |
if ($cancelled || $valid) { | |
$closeModal = true; | |
} else { | |
$closeModal = false; | |
if (isset($event['settings']['formTheme'])) { | |
$viewParams['formTheme'] = $event['settings']['formTheme']; | |
} | |
$viewParams['form'] = $form->createView(); | |
$viewParams['eventHeader'] = $this->translator->trans($event['settings']['label']); | |
$viewParams['eventDescription'] = (!empty($event['settings']['description'])) ? $this->translator->trans( | |
$event['settings']['description'] | |
) : ''; | |
} | |
$viewParams['hideTriggerMode'] = isset($event['settings']['hideTriggerMode']) && $event['settings']['hideTriggerMode']; | |
$passthroughVars = [ | |
'mauticContent' => 'campaignEvent', | |
'success' => $success, | |
'route' => false, | |
]; | |
if (!empty($keyId)) { | |
$passthroughVars = array_merge($passthroughVars, $this->eventViewVars($event, $campaignId, 'new')); | |
} | |
if ($closeModal) { | |
// just close the modal | |
$passthroughVars['closeModal'] = 1; | |
return new JsonResponse($passthroughVars); | |
} else { | |
return $this->ajaxAction( | |
$request, | |
[ | |
'contentTemplate' => '@MauticCampaign/Event/form.html.twig', | |
'viewParameters' => $viewParams, | |
'passthroughVars' => $passthroughVars, | |
] | |
); | |
} | |
} | |
/** | |
* Generates edit form and processes post data. | |
* | |
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response | |
*/ | |
public function editAction(Request $request, $objectId) | |
{ | |
$session = $request->getSession(); | |
$valid = $cancelled = false; | |
$method = $request->getMethod(); | |
$campaignEvent = $request->request->get('campaignevent') ?? []; | |
$campaignId = 'POST' === $method | |
? ($campaignEvent['campaignId'] ?? '') | |
: $request->query->get('campaignId'); | |
$modifiedEvents = $session->get('mautic.campaign.'.$campaignId.'.events.modified', []); | |
$event = array_key_exists($objectId, $modifiedEvents) ? $modifiedEvents[$objectId] : []; | |
if ('POST' === $method) { | |
$event = array_merge($event, [ | |
'anchor' => $campaignEvent['anchor'] ?? '', | |
'anchorEventType' => $campaignEvent['anchorEventType'] ?? '', | |
]); | |
} else { | |
if (!isset($event['anchor']) && !empty($event['decisionPath'])) { | |
// Used to generate label | |
$event['anchor'] = $event['decisionPath']; | |
} | |
if ($request->query->has('anchor')) { | |
// Override the anchor | |
$event['anchor'] = $request->get('anchor'); | |
} | |
if ($request->query->has('anchorEventType')) { | |
// Override the anchorEventType | |
$event['anchorEventType'] = $request->get('anchorEventType'); | |
} | |
} | |
/* | |
* If we don't have an event, don't support the event type, this is not an | |
* AJAX request, or we are not granted campaign edit/create, deny access. | |
*/ | |
if (empty($event) | |
|| empty($event['eventType']) | |
|| !in_array($event['eventType'], $this->supportedEventTypes) | |
|| !isset($event['type']) | |
|| !$request->isXmlHttpRequest() | |
|| !$this->security->isGranted( | |
[ | |
'campaign:campaigns:edit', | |
'campaign:campaigns:create', | |
], | |
'MATCH_ONE' | |
) | |
) { | |
return $this->modalAccessDenied(); | |
} | |
/** | |
* Fire the CampaignBuilderEvent event to get all events. | |
* | |
* We can directly dereference the return value here to get | |
* the supported events for this type because we already made | |
* sure that we're accessing a supported event type above. | |
* | |
* Method getEventsArray() returns translated labels & descriptions | |
*/ | |
$supportedEvents = $this->eventCollector->getEventsArray()[$event['eventType']]; | |
$form = $this->formFactory->create( | |
EventType::class, | |
$event, | |
[ | |
'action' => $this->generateUrl('mautic_campaignevent_action', ['objectAction' => 'edit', 'objectId' => $objectId]), | |
'settings' => $supportedEvents[$event['type']], | |
] | |
); | |
$event['settings'] = $supportedEvents[$event['type']]; | |
$form->get('campaignId')->setData($campaignId); | |
// Check for a submitted form and process it | |
if ('POST' === $method) { | |
if (!$cancelled = $this->isFormCancelled($form)) { | |
if ($valid = $this->isFormValid($form)) { | |
$formData = $form->getData(); | |
$event = array_merge($event, $formData); | |
// Set the name to the event default if not known. | |
if (empty($event['name'])) { | |
$event['name'] = $event['settings']['label']; | |
} | |
$modifiedEvents[$objectId] = $event; | |
// Save the modified event properties to session | |
$session->set('mautic.campaign.'.$campaignId.'.events.modified', $modifiedEvents); | |
} | |
} | |
} | |
$viewParams = [ | |
'type' => $event['type'], | |
'hideTriggerMode' => isset($event['settings']['hideTriggerMode']) && $event['settings']['hideTriggerMode'], | |
]; | |
$passthroughVars = [ | |
'mauticContent' => 'campaignEvent', | |
'success' => !$cancelled && $valid, | |
'route' => false, | |
]; | |
if (!$cancelled && !$valid) { | |
if (isset($event['settings']['formTheme'])) { | |
$viewParams['formTheme'] = $event['settings']['formTheme']; | |
} | |
$viewParams = array_merge($viewParams, [ | |
'form' => $form->createView(), | |
'eventHeader' => $event['settings']['label'], | |
'eventDescription' => $event['settings']['description'], | |
]); | |
return $this->ajaxAction( | |
$request, | |
[ | |
'contentTemplate' => '@MauticCampaign/Event/form.html.twig', | |
'viewParameters' => $viewParams, | |
'passthroughVars' => $passthroughVars, | |
] | |
); | |
} | |
if (!$cancelled && $valid) { | |
$passthroughVars = array_merge($passthroughVars, $this->eventViewVars($event, $campaignId, 'edit')); | |
} | |
// Just close the modal | |
$passthroughVars['closeModal'] = 1; | |
return new JsonResponse($passthroughVars); | |
} | |
/** | |
* Deletes the entity. | |
* | |
* @return JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse | |
*/ | |
public function deleteAction(Request $request, $objectId) | |
{ | |
$campaignId = $request->query->get('campaignId'); | |
$session = $request->getSession(); | |
$modifiedEvents = $session->get('mautic.campaign.'.$campaignId.'.events.modified', []); | |
$deletedEvents = $session->get('mautic.campaign.'.$campaignId.'.events.deleted', []); | |
// ajax only for form fields | |
if (!$request->isXmlHttpRequest() | |
|| !$this->security->isGranted( | |
[ | |
'campaign:campaigns:edit', | |
'campaign:campaigns:create', | |
], | |
'MATCH_ONE' | |
) | |
) { | |
return $this->accessDenied(); | |
} | |
$event = (array_key_exists($objectId, $modifiedEvents)) ? $modifiedEvents[$objectId] : null; | |
if ('POST' == $request->getMethod() && null !== $event) { | |
$events = $this->eventCollector->getEventsArray(); | |
$event['settings'] = $events[$event['eventType']][$event['type']]; | |
// Add the field to the delete list | |
if (!in_array($objectId, $deletedEvents)) { | |
// If event is new don't add to deleted list | |
if (!str_contains($objectId, 'new')) { | |
$deletedEvents[] = $objectId; | |
$session->set('mautic.campaign.'.$campaignId.'.events.deleted', $deletedEvents); | |
} | |
// Always remove from modified list if deleted | |
if (isset($modifiedEvents[$objectId])) { | |
unset($modifiedEvents[$objectId]); | |
$session->set('mautic.campaign.'.$campaignId.'.events.modified', $modifiedEvents); | |
} | |
} | |
$dataArray = [ | |
'mauticContent' => 'campaignEvent', | |
'success' => 1, | |
'route' => false, | |
'eventId' => $objectId, | |
'deleted' => 1, | |
'event' => $event, | |
]; | |
} else { | |
$dataArray = ['success' => 0]; | |
} | |
return new JsonResponse($dataArray); | |
} | |
/** | |
* Undeletes the entity. | |
* | |
* @return JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse | |
*/ | |
public function undeleteAction(Request $request, $objectId) | |
{ | |
$campaignId = $request->query->get('campaignId'); | |
$session = $request->getSession(); | |
$modifiedEvents = $session->get('mautic.campaign.'.$campaignId.'.events.modified', []); | |
$deletedEvents = $session->get('mautic.campaign.'.$campaignId.'.events.deleted', []); | |
// ajax only for form fields | |
if (!$request->isXmlHttpRequest() | |
|| !$this->security->isGranted( | |
[ | |
'campaign:campaigns:edit', | |
'campaign:campaigns:create', | |
], | |
'MATCH_ONE' | |
) | |
) { | |
return $this->accessDenied(); | |
} | |
$event = (array_key_exists($objectId, $modifiedEvents)) ? $modifiedEvents[$objectId] : null; | |
if ('POST' == $request->getMethod() && null !== $event) { | |
$events = $this->eventCollector->getEventsArray(); | |
$event['settings'] = $events[$event['eventType']][$event['type']]; | |
// add the field to the delete list | |
if (in_array($objectId, $deletedEvents)) { | |
$key = array_search($objectId, $deletedEvents); | |
unset($deletedEvents[$key]); | |
$session->set('mautic.campaign.'.$campaignId.'.events.deleted', $deletedEvents); | |
} | |
$template = (empty($event['settings']['template'])) ? '@MauticCampaign/Event/_generic.html.twig' | |
: $event['settings']['template']; | |
// prevent undefined errors | |
$entity = new Event(); | |
$blank = $entity->convertToArray(); | |
$event = array_merge($blank, $event); | |
$dataArray = [ | |
'mauticContent' => 'campaignEvent', | |
'success' => 1, | |
'route' => false, | |
'eventId' => $objectId, | |
'eventHtml' => $this->renderView( | |
$template, | |
[ | |
'event' => $event, | |
'id' => $objectId, | |
'campaignId' => $campaignId, | |
] | |
), | |
]; | |
} else { | |
$dataArray = ['success' => 0]; | |
} | |
return new JsonResponse($dataArray); | |
} | |
public function cloneAction(Request $request, string $objectId): JsonResponse | |
{ | |
$campaignId = $request->query->get('campaignId'); | |
$session = $request->getSession(); | |
$modifiedEvents = $session->get('mautic.campaign.'.$campaignId.'.events.modified', []); | |
$campaign = $this->campaignModel->getEntity($campaignId); | |
// ajax only for form fields | |
if (!$request->isXmlHttpRequest() | |
|| !$this->security->isGranted( | |
[ | |
'campaign:campaigns:edit', | |
'campaign:campaigns:create', | |
], | |
'MATCH_ONE' | |
) | |
) { | |
return $this->accessDenied(); | |
} | |
$event = (array_key_exists($objectId, $modifiedEvents)) ? $modifiedEvents[$objectId] : null; | |
if ('POST' == $request->getMethod() && null !== $event) { | |
$keyId = 'new'.hash('sha1', uniqid((string) mt_rand())); | |
$event['id'] = $event['tempId'] = $keyId; | |
$session->set('mautic.campaign.events.clone.storage', $event); | |
$dataArray = [ | |
'success' => 1, | |
'mauticContent' => 'campaignEventClone', | |
'route' => false, | |
'eventId' => $objectId, | |
'eventName' => $event['name'], | |
'eventType' => $event['eventType'], | |
'type' => $event['type'], | |
'campaignId' => $campaign ? $campaign->getId() : $campaignId, | |
'campaignName' => $campaign ? $campaign->getName() : $this->translator->trans('mautic.campaign.event.clone.new.campaign'), | |
]; | |
} else { | |
$dataArray = ['success' => 0]; | |
} | |
return new JsonResponse($dataArray); | |
} | |
public function insertAction(Request $request): JsonResponse | |
{ | |
$campaignId = $request->query->get('campaignId'); | |
$session = $request->getSession(); | |
$modifiedEvents = $session->get('mautic.campaign.'.$campaignId.'.events.modified', []); | |
$event = $session->get('mautic.campaign.events.clone.storage'); | |
if (empty($event)) { | |
return new JsonResponse([ | |
'error' => $this->translator->trans('mautic.campaign.event.clone.request.missing'), | |
], 400); | |
} | |
$session->remove('mautic.campaign.events.clone.storage'); | |
$keyId = 'new'.hash('sha1', uniqid((string) mt_rand())); | |
$event['id'] = $event['tempId'] = $keyId; | |
$modifiedEvents[$keyId] = $event; | |
$session->set('mautic.campaign.'.$campaignId.'.events.modified', $modifiedEvents); | |
$passThroughVars = [ | |
'mauticContent' => 'campaignEvent', | |
'clearCloneStorage' => true, | |
'success' => 1, | |
'route' => false, | |
]; | |
$passThroughVars = array_merge($passThroughVars, $this->eventViewVars($event, $campaignId, 'insert')); | |
return new JsonResponse($passThroughVars); | |
} | |
/** | |
* @param array<string, mixed> $event | |
* | |
* @return array<string, mixed> | |
*/ | |
private function eventViewVars( | |
array $event, | |
string $campaignId, | |
string $action | |
): array { | |
// Merge default event properties with provided event data | |
$event = array_merge((new Event())->convertToArray(), $event); | |
// Determine the template | |
$template = $event['settings']['template'] ?? '@MauticCampaign/Event/_generic.html.twig'; | |
// Prepare common template variables | |
$templateVars = [ | |
'event' => $event, | |
'id' => $event['id'], | |
'campaignId' => $campaignId, | |
]; | |
if ('edit' === $action) { | |
$templateVars['update'] = true; | |
} | |
// Render the template and store it in the appropriate variable | |
$passThroughKey = ('edit' === $action) ? 'updateHtml' : 'eventHtml'; | |
$passThroughVars[$passThroughKey] = $this->renderView($template, $templateVars); | |
// Pass through event-related variables | |
$passThroughVars += [ | |
'event' => $event, | |
'eventId' => $event['id'], | |
'eventType' => $event['eventType'], | |
]; | |
// Handle trigger mode interval | |
if (Event::TRIGGER_MODE_INTERVAL === $event['triggerMode']) { | |
$label = 'mautic.campaign.connection.trigger.interval.label'; | |
if (Event::PATH_INACTION === $event['anchor']) { | |
$label .= '_inaction'; | |
} | |
$passThroughVars['label'] = $this->translator->trans( | |
$label, | |
[ | |
'%number%' => $event['triggerInterval'], | |
'%unit%' => $this->translator->trans( | |
'mautic.campaign.event.intervalunit.'.$event['triggerIntervalUnit'], | |
['%count%' => $event['triggerInterval']] | |
), | |
] | |
); | |
} | |
// Handle trigger mode date | |
if (Event::TRIGGER_MODE_DATE === $event['triggerMode']) { | |
$label = 'mautic.campaign.connection.trigger.date.label'; | |
if (Event::PATH_INACTION === $event['anchor']) { | |
$label .= '_inaction'; | |
} | |
$passThroughVars['label'] = $this->translator->trans( | |
$label, | |
[ | |
'%full%' => $this->dateHelper->toFull($event['triggerDate']), | |
'%time%' => $this->dateHelper->toTime($event['triggerDate']), | |
'%date%' => $this->dateHelper->toShort($event['triggerDate']), | |
] | |
); | |
} | |
return $passThroughVars; | |
} | |
} | |