/** * Finds a Location by the URL and automatically creates the Location if it * does not exist and if the respective Location module supports auto * generation of Locations. ** * @param $url * @param $operation Operation * @return bool|Location|null|object */ public function findLocationByUrl($url, $operation, $alias = null) { $url = ParserUtil::sanitizeUrl($url); /* * If not a Location, then see if the URL is inside a connected * Channel's top-level Locations. To do so, check if one of these * criteria apply: * - The Location URL matches the beginning of the CTA URL * - The Location identifier is included in the CTA URL as well * as the domain */ if (ParserUtil::urlExists($url)) { $urlParts = parse_url($url); if ($urlParts['scheme'] == 'http') { $urlAltScheme = str_replace('http://', 'https://', $url); } elseif ($urlParts['scheme'] == 'https') { $urlAltScheme = str_replace('https://', 'http://', $url); } $repository = $this->em->getRepository('CampaignChainCoreBundle:Location'); $query = $repository->createQueryBuilder('location')->where("(:url LIKE CONCAT('%', location.url, '%')) OR " . "(:url_alt_scheme LIKE CONCAT('%', location.url, '%')) OR " . "(" . "location.identifier IS NOT NULL AND " . ":url LIKE CONCAT('%', location.identifier, '%') AND " . "location.url LIKE :host" . ")")->andWhere('location.parent IS NULL')->setParameter('url', $url)->setParameter('url_alt_scheme', $urlAltScheme)->setParameter('host', $urlParts['host'] . '%')->getQuery(); /** @var Location $matchingLocation */ $matchingLocation = $query->getOneOrNullResult(); if ($matchingLocation) { /* * Create a new Location based on the tracking alias * within the matching Location's Channel. * * If no tracking alias was provided, we take the * default LocationModule to create a new Location. */ if (!$alias) { // Done if the URL is exactly the same in the matching Location. if ($matchingLocation->getUrl() == $url || $matchingLocation->getUrl() == $urlAltScheme) { return $matchingLocation; } // Let's move on to create a new Location with the default module. $locationService = $this->container->get('campaignchain.core.location'); /** @var LocationModule $locationModule */ $locationModule = $locationService->getLocationModule(self::DEFAULT_LOCATION_BUNDLE_NAME, self::DEFAULT_LOCATION_MODULE_IDENTIFIER); if (!$locationModule) { throw new \Exception('No Location module found for bundle "' . $matchingLocation->getChannel()->getBundle()->getName() . ' and module ' . $matchingLocation->getChannel()->getChannelModule()->getIdentifier() . '"'); } } else { /* * Get the Location module within the matching Location's * Channel and with the given tracking alias. */ /** @var LocationModule $locationModule */ $locationModule = $this->getLocationModuleByTrackingAlias($matchingLocation->getChannel()->getChannelModule(), $alias); // Done if the matching Location also matches the alias and URL. if ($matchingLocation->getLocationModule() == $locationModule && ($matchingLocation->getUrl() == $url || $matchingLocation->getUrl() == $urlAltScheme)) { return $matchingLocation; } /* * See if there is already another Location that matches the * aliase's Location module and the URL. */ $repository = $this->em->getRepository('CampaignChainCoreBundle:Location'); $query = $repository->createQueryBuilder('location')->where('location.locationModule = :locationModule')->andWhere('(location.url = :url OR location.url = :url_alt_scheme')->setParameter('locationModule', $locationModule)->setParameter('url', $url)->setParameter('url_alt_scheme', $urlAltScheme)->getQuery(); /** @var Location $location */ $location = $query->getOneOrNullResult(); // We found an existing Location, we're done. if ($location) { return $location; } if (!$locationModule) { throw new \Exception('Cannot map tracking alias "' . $alias . '" to a "' . 'Location module that belongs to Channel module "' . $matchingLocation->getChannel()->getBundle()->getName() . '/' . $matchingLocation->getChannel()->getChannelModule()->getIdentifier() . '"'); } } /* * If the matching Location provides auto-generation of Locations, * then let's create a new child Location. */ $ctaServiceName = $locationModule->getServices()['job_cta']; if ($ctaServiceName) { // Create the new Location $location = new Location(); $location->setUrl($url); $location->setOperation($operation); $location->setChannel($matchingLocation->getChannel()); $location->setParent($matchingLocation); // Update the Location module to be the current // one. $location->setLocationModule($locationModule); // Let the module's service process the new // Location. $ctaService = $this->container->get($ctaServiceName); return $ctaService->execute($location); } else { throw new \Exception('No CTA Job service defined for Location module ' . 'of bundle "' . $locationModule->getBundle()->getName() . '" ' . 'and module "' . $locationModule->getIdentifier() . '"'); } } else { return false; } } throw new \Exception('The URL ' . $url . ' does not exist.'); }
public function createActivity(Activity $activity, Form $form) { // Apply context of Activity. if (!$activity->getCampaign()) { $activity->setCampaign($this->campaign); } elseif (!$this->campaign) { $this->campaign = $activity->getCampaign(); } if (!$activity->getChannel()) { $activity->setChannel($this->channel); } elseif (!$this->channel) { $this->channel = $activity->getChannel(); } if (!$activity->getLocation()) { $activity->setLocation($this->location); } elseif (!$this->location) { $this->location = $activity->getLocation(); } // The Module's content. $content = null; // If Activity module is not set, then do it. if (!$activity->getActivityModule()) { $moduleService = $this->get('campaignchain.core.module'); $activity->setActivityModule($moduleService->getModule($this->activityBundleName, $this->activityModuleIdentifier)); } // Does the Activity module relate to at least one Channel module? $hasChannel = $activity->getActivityModule()->getChannelModules()->count(); // The Module's content. $content = null; $operation = new Operation(); if ($this->parameters['equals_operation']) { if ($hasChannel) { if (!$activity->getChannel()) { $activity->setChannel($this->channel); } elseif (!$this->channel) { $this->channel = $activity->getChannel(); } if (!$activity->getLocation()) { $activity->setLocation($this->location); } elseif (!$this->location) { $this->location = $activity->getLocation(); } } // Allow the module to change some data based on its custom input. if ($form->has($this->contentModuleFormName)) { $this->handler->postFormSubmitNewEvent($activity, $form->get($this->contentModuleFormName)->getData()); // Allow a module's handler to modify the Activity data. $activity = $this->handler->processActivity($activity, $form->get($this->contentModuleFormName)->getData()); } // Get the operation module. $operationService = $this->get('campaignchain.core.operation'); $operation = $operationService->newOperationByActivity($activity, $this->contentBundleName, $this->contentModuleIdentifier); // Will the Operation create a Location, i.e. the Operation // will be accessible through a URL after publishing? if ($operation->getOperationModule()->ownsLocation()) { // Get the location module. $locationService = $this->get('campaignchain.core.location'); $locationModule = $locationService->getLocationModule($this->locationBundleName, $this->locationModuleIdentifier); $contentLocation = new Location(); $contentLocation->setLocationModule($locationModule); $contentLocation->setParent($activity->getLocation()); $contentLocation->setName($activity->getName()); $contentLocation->setStatus(Medium::STATUS_UNPUBLISHED); $contentLocation->setOperation($operation); $operation->addLocation($contentLocation); if ($form->has($this->contentModuleFormName)) { // Allow a module's handler to modify the Operation's Location. $contentLocation = $this->handler->processContentLocation($contentLocation, $form->get($this->contentModuleFormName)->getData()); } } if ($form->has($this->contentModuleFormName)) { // Process the Operation's content. $content = $this->handler->processContent($operation, $form->get($this->contentModuleFormName)->getData()); } if ($content) { // Link the Operation details with the operation. $content->setOperation($operation); } } elseif (count($this->parameters['operations']) > 1) { $content = $this->handler->processMultiOperationMultiContent($activity, $form, $this->parameters['operations']); } $em = $this->getDoctrine()->getManager(); // Make sure that data stays intact by using transactions. try { $em->getConnection()->beginTransaction(); $em->persist($activity); if (!$content) { $content = $this->handler->processSingleContentMultiOperation($activity, $form); } if ($content) { $em->persist($content); } // We need the activity ID for storing the hooks. Hence we must // flush here. $em->flush(); $hookService = $this->get('campaignchain.core.hook'); /** @var Activity $activity */ $activity = $hookService->processHooks($this->parameters['bundle_name'], $this->parameters['module_identifier'], $activity, $form, true); // Check if the content can be executed. if (isset($this->validators['operations']) && $content) { $isExecutable = $this->validators['operations'][0]->isExecutableByLocation($content, $activity->getStartDate()); if (!$isExecutable['status']) { throw new \Exception($isExecutable['message']); } $activity->setMustValidate($this->validators['operations'][0]->mustValidate($content, $activity->getStartDate())); } $em->flush(); $em->getConnection()->commit(); } catch (\Exception $e) { $em->getConnection()->rollback(); throw $e; } // The module tries to execute the job immediately. $this->handler->postPersistNewEvent($operation, $form, $content); return $activity; }