/** * @param Bundle $newBundle * @return string */ public function isRegisteredBundle(Bundle $newBundle) { /** @var Bundle $registeredBundle */ $registeredBundle = $this->em->getRepository('CampaignChainCoreBundle:Bundle')->findOneByName($newBundle->getName()); if (!$registeredBundle) { // This case covers development of modules. return Installer::STATUS_REGISTERED_NO; } /* * Checking for dev-* ensures that the status is being registered * properly not just for dev-master, but also for branches (e.g. * dev-campaignchain-42). */ if (substr($registeredBundle->getVersion(), 0, 4) === "dev-" && substr($newBundle->getVersion(), 0, 4) === "dev-") { return Installer::STATUS_REGISTERED_OLDER; } // Bundle with same version is already registered. if (version_compare($registeredBundle->getVersion(), $newBundle->getVersion(), '==')) { return Installer::STATUS_REGISTERED_SAME; } // Bundle with older version is already registered. return Installer::STATUS_REGISTERED_OLDER; }
/** * @param Bundle $bundle * * @throws \Exception */ private function registerModule(Bundle $bundle) { $params = $this->getModule($this->rootDir . $bundle->getPath() . DIRECTORY_SEPARATOR . 'campaignchain.yml'); // General installation routine. if (!is_array($params['modules']) || !count($params['modules'])) { return; } foreach ($params['modules'] as $identifier => $moduleParams) { $module = null; if ($bundle->getStatus()) { $status = $bundle->getStatus(); } else { $status = $this->bundleConfigService->isRegisteredBundle($bundle); } /* * TODO: Detect whether a module has previously been registered * for this bundle, but the module is not anymore defined in * its campaignchain.yml. */ if ($status == self::STATUS_REGISTERED_OLDER) { /** @var Module $module */ $module = $this->em->getRepository('CampaignChainCoreBundle:Module')->findOneBy(['bundle' => $bundle, 'identifier' => strtolower($identifier)]); } switch ($bundle->getType()) { case 'campaignchain-channel': $moduleEntity = 'ChannelModule'; break; case 'campaignchain-location': $moduleEntity = 'LocationModule'; break; case 'campaignchain-campaign': $moduleEntity = 'CampaignModule'; break; case 'campaignchain-milestone': $moduleEntity = 'MilestoneModule'; break; case 'campaignchain-activity': $moduleEntity = 'ActivityModule'; break; case 'campaignchain-operation': $moduleEntity = 'OperationModule'; break; case 'campaignchain-report': case 'campaignchain-report-analytics': case 'campaignchain-report-budget': case 'campaignchain-report-sales': $moduleEntity = 'ReportModule'; break; case 'campaignchain-security': $moduleEntity = 'SecurityModule'; break; } if (!$module) { $entityClass = 'CampaignChain\\CoreBundle\\Entity\\' . $moduleEntity; /** @var Module $module */ $module = new $entityClass(); $module->setIdentifier(strtolower($identifier)); $module->setBundle($bundle); } $module->setDisplayName($moduleParams['display_name']); /* * Tracking alias which allows the CTA tracking to match the * Location Identifier provided by the tracking script to a module. */ if (isset($moduleParams['tracking_alias']) && strlen($moduleParams['tracking_alias'])) { $module->setTrackingAlias($moduleParams['tracking_alias']); } if (isset($moduleParams['description'])) { $module->setDescription($moduleParams['description']); } // Verify routes. if (in_array($bundle->getType(), ['campaignchain-activity', 'campaignchain-channel', 'campaignchain-campaign', 'campaignchain-milestone'])) { // Throw error if no routes defined. if (!isset($moduleParams['routes']) || !is_array($moduleParams['routes']) || !count($moduleParams['routes'])) { throw new \Exception('The module "' . $identifier . '" in bundle "' . $bundle->getName() . '"' . ' does not provide any of the required routes.'); } else { // Throw error if one or more routes are missing. $hasMissingRoutes = false; $missingRoutes = ''; foreach ($this->requiredRoutes[$bundle->getType()] as $requiredRoute) { if (!array_key_exists($requiredRoute, $moduleParams['routes'])) { $hasMissingRoutes = true; $missingRoutes .= $requiredRoute . ', '; } } if ($hasMissingRoutes) { throw new \Exception('The module "' . $identifier . '" in bundle "' . $bundle->getName() . '"' . ' must define the following route(s): ' . rtrim($missingRoutes, ', ') . '.'); } else { $module->setRoutes($moduleParams['routes']); } } } elseif (isset($moduleParams['routes']) && is_array($moduleParams['routes']) && count($moduleParams['routes'])) { $module->setRoutes($moduleParams['routes']); } if (isset($moduleParams['services']) && is_array($moduleParams['services']) && count($moduleParams['services'])) { $module->setServices($moduleParams['services']); } if (isset($moduleParams['hooks']) && is_array($moduleParams['hooks']) && count($moduleParams['hooks'])) { // TODO: Check that there's only 1 trigger hook included. $module->setHooks($moduleParams['hooks']); } if (isset($moduleParams['system']) && is_array($moduleParams['system']) && count($moduleParams['system'])) { $this->systemParams[] = $moduleParams['system']; } // Are metrics for the reports defined? if (isset($moduleParams['metrics']) && is_array($moduleParams['metrics']) && count($moduleParams['metrics'])) { foreach ($moduleParams['metrics'] as $metricType => $metricNames) { switch ($metricType) { case 'activity': $metricClass = 'ReportAnalyticsActivityMetric'; break; case 'location': $metricClass = 'ReportAnalyticsLocationMetric'; break; default: throw new \Exception("Unknown metric type '" . $metricType . "'." . "Pick 'activity' or 'location' instead."); break; } foreach ($metricNames as $metricName) { $metric = $this->em->getRepository('CampaignChainCoreBundle:' . $metricClass)->findOneBy(['name' => $metricName, 'bundle' => $bundle->getName()]); // Does the metric already exist? if ($metric) { /* * Throw error if bundle is new and metric * has already been registered. */ if ($status == self::STATUS_REGISTERED_NO) { throw new \Exception("Metric '" . $metricName . "' of type '" . $metricType . "'" . ' already exists for bundle ' . $bundle->getName() . '. ' . 'Please define another name ' . 'in campaignchain.yml of ' . $bundle->getName() . '.'); } // Skip if same or older version of bundle. continue; } else { // Create new metric. $metricNamespacedClass = 'CampaignChain\\CoreBundle\\Entity\\' . $metricClass; $metric = new $metricNamespacedClass(); $metric->setName($metricName); $metric->setBundle($bundle->getName()); $this->em->persist($metric); } } } } // Process the params specific to a module type. // Params that must be defined for Operation modules if ($bundle->getType() == 'campaignchain-operation' && !isset($moduleParams['params']['owns_location'])) { throw new \Exception("You must set the 'owns_location' parameter in campaignchain.yml to 'true' or 'false' for module '" . $identifier . "' in bundle '" . $bundle->getName() . "'."); } if (isset($moduleParams['params'])) { $module->setParams($moduleParams['params']); } // Add new module to new bundle. $reflect = new \ReflectionClass($module); $addModuleMethod = 'add' . $reflect->getShortName(); $bundle->{$addModuleMethod}($module); // If a campaign module, remember the conversion to other campaign types. if ($bundle->getType() == 'campaignchain-campaign' && isset($moduleParams['conversions']) && is_array($moduleParams['conversions']) && count($moduleParams['conversions'])) { $this->campaignConversions[$bundle->getName()][$module->getIdentifier()] = $moduleParams['conversions']; } // If an activity or Location module, remember the related channels. if (isset($moduleParams['channels']) && is_array($moduleParams['channels']) && count($moduleParams['channels'])) { $this->channelRelationships[$moduleEntity][$bundle->getName()][$module->getIdentifier()] = $moduleParams['channels']; } } }