![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/mautic.corals.io/app/bundles/CampaignBundle/Executioner/ |
<?php namespace Mautic\CampaignBundle\Executioner; use Doctrine\Common\Collections\ArrayCollection; use Mautic\CampaignBundle\Entity\Event; use Mautic\CampaignBundle\Entity\EventRepository; use Mautic\CampaignBundle\EventCollector\Accessor\Event\DecisionAccessor; use Mautic\CampaignBundle\EventCollector\EventCollector; use Mautic\CampaignBundle\Executioner\Event\DecisionExecutioner as Executioner; use Mautic\CampaignBundle\Executioner\Exception\CampaignNotExecutableException; use Mautic\CampaignBundle\Executioner\Exception\DecisionNotApplicableException; use Mautic\CampaignBundle\Executioner\Helper\DecisionHelper; use Mautic\CampaignBundle\Executioner\Result\Responses; use Mautic\CampaignBundle\Executioner\Scheduler\EventScheduler; use Mautic\CampaignBundle\Helper\ChannelExtractor; use Mautic\LeadBundle\Entity\Lead; use Mautic\LeadBundle\Model\LeadModel; use Mautic\LeadBundle\Tracker\ContactTracker; use Psr\Log\LoggerInterface; class RealTimeExecutioner { /** * @var Lead */ private $contact; /** * @var array */ private $events; private ?Responses $responses = null; public function __construct( private LoggerInterface $logger, private LeadModel $leadModel, private EventRepository $eventRepository, private EventExecutioner $executioner, private Executioner $decisionExecutioner, private EventCollector $collector, private EventScheduler $scheduler, private ContactTracker $contactTracker, private DecisionHelper $decisionHelper ) { } /** * @param string $type * @param mixed $passthrough * @param string|null $channel * @param int|null $channelId * * @return Responses * * @throws Dispatcher\Exception\LogNotProcessedException * @throws Dispatcher\Exception\LogPassedAndFailedException * @throws Exception\CannotProcessEventException * @throws Scheduler\Exception\NotSchedulableException */ public function execute($type, $passthrough = null, $channel = null, $channelId = null) { $this->responses = new Responses(); $now = new \DateTime(); $this->logger->debug('CAMPAIGN: Campaign triggered for event type '.$type.'('.$channel.' / '.$channelId.')'); // Kept for BC support although not sure we need this defined('MAUTIC_CAMPAIGN_NOT_SYSTEM_TRIGGERED') or define('MAUTIC_CAMPAIGN_NOT_SYSTEM_TRIGGERED', 1); try { $this->fetchCurrentContact(); } catch (CampaignNotExecutableException $exception) { $this->logger->debug('CAMPAIGN: '.$exception->getMessage()); return $this->responses; } try { $this->fetchCampaignData($type); } catch (CampaignNotExecutableException $exception) { $this->logger->debug('CAMPAIGN: '.$exception->getMessage()); return $this->responses; } /** @var Event $event */ foreach ($this->events as $event) { try { $this->evaluateDecisionForContact($event, $passthrough, $channel, $channelId); } catch (DecisionNotApplicableException $exception) { $this->logger->debug('CAMPAIGN: Event ID '.$event->getId().' is not applicable ('.$exception->getMessage().')'); continue; } $children = $event->getPositiveChildren(); if (!$children->count()) { $this->logger->debug('CAMPAIGN: Event ID '.$event->getId().' has no positive children'); continue; } $this->executeAssociatedEvents($children, $now); } // Save any changes to the contact done by the listeners if ($this->contact->getChanges()) { $this->leadModel->saveEntity($this->contact, false); } return $this->responses; } /** * @throws Dispatcher\Exception\LogNotProcessedException * @throws Dispatcher\Exception\LogPassedAndFailedException * @throws Exception\CannotProcessEventException * @throws Scheduler\Exception\NotSchedulableException */ private function executeAssociatedEvents(ArrayCollection $children, \DateTime $now): void { $children = clone $children; /** @var Event $child */ foreach ($children as $key => $child) { $executionDate = $this->scheduler->getExecutionDateTime($child, $now); $this->logger->debug( 'CAMPAIGN: Event ID# '.$child->getId(). ' to be executed on '.$executionDate->format('Y-m-d H:i:s e') ); if ($this->scheduler->shouldSchedule($executionDate, $now)) { $this->scheduler->scheduleForContact($child, $executionDate, $this->contact); $children->remove($key); } } if ($children->count()) { $this->executioner->executeEventsForContact($children, $this->contact, $this->responses); } } /** * @param mixed $passthrough * @param string|null $channel * @param int|null $channelId * * @throws DecisionNotApplicableException * @throws Exception\CannotProcessEventException */ private function evaluateDecisionForContact(Event $event, $passthrough = null, $channel = null, $channelId = null): void { $this->logger->debug('CAMPAIGN: Executing '.$event->getType().' ID '.$event->getId().' for contact ID '.$this->contact->getId()); $this->decisionHelper->checkIsDecisionApplicableForContact($event, $this->contact, $channel, $channelId); /** @var DecisionAccessor $config */ $config = $this->collector->getEventConfig($event); $this->decisionExecutioner->evaluateForContact($config, $event, $this->contact, $passthrough, $channel, $channelId); } /** * @throws CampaignNotExecutableException */ private function fetchCurrentContact(): void { $this->contact = $this->contactTracker->getContact(); if (!$this->contact instanceof Lead || !$this->contact->getId()) { throw new CampaignNotExecutableException('Unidentifiable contact'); } $this->logger->debug('CAMPAIGN: Current contact ID# '.$this->contact->getId()); } /** * @throws CampaignNotExecutableException */ private function fetchCampaignData($type): void { if (!$this->events = $this->eventRepository->getContactPendingEvents($this->contact->getId(), $type)) { throw new CampaignNotExecutableException('Contact does not have any applicable '.$type.' associations.'); } // 2.14 BC break workaround - pre 2.14 had a bug that recorded channelId for decisions as 1 regardless of actually ID // if channelIdField was an array and only one item was selected. That caused the channel ID check in evaluateDecisionForContact // to fail resulting in the decision never being evaluated. Therefore we are going to self heal these decisions. /** @var Event $event */ foreach ($this->events as $event) { if (1 === $event->getChannelId()) { ChannelExtractor::setChannel($event, $event, $this->collector->getEventConfig($event)); $this->eventRepository->saveEntity($event); } } $this->logger->debug('CAMPAIGN: Found '.count($this->events).' events to analyze for contact ID '.$this->contact->getId()); } }