/** * @param SymfonyStyle|null $io */ public function updateCode(SymfonyStyle $io = null) { $io->title('CampaignChain Data Update'); if (empty($this->versions)) { $io->warning('No code updater Service found, maybe you didn\'t enable a bundle?'); return; } $io->comment('The following data versions will be updated'); $migratedVersions = array_map(function (DataUpdateVersion $version) { return $version->getVersion(); }, $this->em->getRepository('CampaignChainUpdateBundle:DataUpdateVersion')->findAll()); $updated = false; foreach ($this->versions as $version => $class) { if (in_array($version, $migratedVersions)) { continue; } $io->section('Version ' . $class->getVersion()); $io->listing($class->getDescription()); $io->text('Begin data update'); $result = $class->execute($io); if ($result) { $dbVersion = new DataUpdateVersion(); $dbVersion->setVersion($version); $this->em->persist($dbVersion); $this->em->flush(); $io->text('Data update finished'); } $updated = true; } if (!$updated) { $io->success('All data is up to date.'); } else { $io->success('Every data version has been updated.'); } }
public function execute(SymfonyStyle $io = null) { $currentProfiles = $this->em->getRepository('CampaignChainLocationGoogleAnalyticsBundle:Profile')->findAll(); if (empty($currentProfiles)) { $io->text('There is no Profile entity to update'); return true; } foreach ($currentProfiles as $profile) { if (substr($profile->getProfileId(), 0, 2) != 'UA') { continue; } $profile->setPropertyId($profile->getProfileId()); $gaProfileUrl = $profile->getLocation()->getUrl(); $google_base_url = 'https:\\/\\/www.google.com\\/analytics\\/web\\/#report\\/visitors-overview\\/a' . $profile->getAccountId() . 'w\\d+p'; $pattern = '/' . $google_base_url . '(.*)/'; preg_match($pattern, $gaProfileUrl, $matches); if (!empty($matches) && count($matches) == 2) { $profile->setProfileId($matches[1]); $profile->setIdentifier($profile->getProfileId()); } $this->em->persist($profile); } $this->em->flush(); return true; }
/** * @param $id * @return \CampaignChain\Operation\LinkedInBundle\Entity\NewsItem * @throws \Exception * @deprecated Use getContent(Operation $operation) instead. */ public function getNewsItemByOperation($id) { $newsitem = $this->em->getRepository('CampaignChainOperationLinkedInBundle:NewsItem')->findOneByOperation($id); if (!$newsitem) { throw new \Exception('No news item found by operation id ' . $id); } return $newsitem; }
/** * @param string $operationId * @return string * @throws \Exception */ public function execute($operationId) { /** @var NewsItem $newsItem */ $newsItem = $this->em->getRepository('CampaignChainOperationLinkedInBundle:NewsItem')->findOneByOperation($operationId); if (!$newsItem) { throw new \Exception('No news item found for an operation with ID: ' . $operationId); } //have images? $images = $this->em->getRepository('CampaignChainHookImageBundle:Image')->getImagesForOperation($newsItem->getOperation()); // if the message does not contain a url, we need to skip the content block if (is_null($newsItem->getLinkUrl())) { // LinkedIn accepts an image link only if we also provided a submitted URL. if ($images) { throw new \Exception('To include an image, you must also provide a URL in the text message.'); return self::STATUS_WARNING; } $content = ['comment' => $newsItem->getMessage(), 'visibility' => ['code' => 'anyone']]; } else { /* * process urls and add tracking * important: both the urls in the message and submitted url field must be identical */ $newsItem->setLinkUrl($this->ctaService->processCTAs($newsItem->getLinkUrl(), $newsItem->getOperation())->getContent()); $newsItem->setMessage($this->ctaService->processCTAs($newsItem->getMessage(), $newsItem->getOperation())->getContent()); $content = ['comment' => $newsItem->getMessage(), 'content' => ['title' => $newsItem->getLinkTitle(), 'description' => $newsItem->getLinkDescription(), 'submitted-url' => $newsItem->getLinkUrl()], 'visibility' => ['code' => 'anyone']]; if ($images) { //Linkedin can handle only 1 image $content['content']['submitted-image-url'] = $this->cacheManager->getBrowserPath($images[0]->getPath(), "campaignchain_linkedin_news_item"); } } $activity = $newsItem->getOperation()->getActivity(); $locationModuleIdentifier = $activity->getLocation()->getLocationModule()->getIdentifier(); $isCompanyPageShare = 'campaignchain-linkedin-page' == $locationModuleIdentifier; $connection = $this->client->getConnectionByActivity($activity); if ($isCompanyPageShare) { $response = $connection->shareOnCompanyPage($activity, $content); } else { $response = $connection->shareOnUserPage($content); } $newsItem->setUrl($response['updateUrl']); $newsItem->setUpdateKey($response['updateKey']); // Set Operation to closed. $newsItem->getOperation()->setStatus(Action::STATUS_CLOSED); $location = $newsItem->getOperation()->getLocations()[0]; $location->setIdentifier($response['updateKey']); $location->setUrl($response['updateUrl']); $location->setName($newsItem->getOperation()->getName()); $location->setStatus(Medium::STATUS_ACTIVE); // Schedule data collection for report $this->reportShareNewsItem->schedule($newsItem->getOperation()); $this->em->flush(); $this->message = 'The message "' . $newsItem->getMessage() . '" with the ID "' . $newsItem->getUpdateKey() . '" has been posted on LinkedIn. See it on LinkedIn: <a href="' . $newsItem->getUrl() . '">' . $newsItem->getUrl() . '</a>'; return self::STATUS_OK; }
/** * Checks whether the Activities belonging to a Campaign and marked with * mustValidate are executable. * * @param Campaign $campaign * @return array */ public function hasExecutableActivities(Campaign $campaign) { $activities = $this->em->getRepository('CampaignChainCoreBundle:Activity')->findBy(array('campaign' => $campaign, 'mustValidate' => true)); if (count($activities)) { foreach ($activities as $activity) { $isExecutable = $this->activityService->isExecutableByCampaign($activity); if (!$isExecutable['status']) { return $isExecutable; } } } return array('status' => true); }
/** * @param Token $newToken * @param bool $sameToken * @return bool|string */ public function setToken(Token $newToken, $sameToken = false) { if ($newToken->getLocation()) { $this->em->persist($newToken); $this->em->flush(); return true; } // Check whether the token already exists in relation to a channel. $repository = $this->em->getRepository('CampaignChainSecurityAuthenticationClientOAuthBundle:Token'); $query = $repository->createQueryBuilder('token')->where('token.application = :application')->andWhere('token.accessToken = :accessToken')->andWhere('token.location IS NOT NULL')->setParameter('application', $newToken->getApplication())->setParameter('accessToken', $newToken->getAccessToken())->setMaxResults(1)->getQuery(); $oldToken = $query->getOneOrNullResult(); if (!$oldToken) { // So, there's no token related to a specific channel, but perhaps there is one // that has been persisted at a previous attempt to connect to the channel? // TODO: Implement what to do if token was persisted previously without channel relationship? $this->token = $newToken; $this->em->persist($this->token); $this->em->flush(); return self::STATUS_NEW_TOKEN; } // Has a scope been set? if (!$newToken->getScope() && !$sameToken) { return self::STATUS_NO_CHANGE; } //With LinkedIn if a user connects multiple times, he will get the same access token //And even though they are same, it has to be saved as a new token if ($sameToken) { $this->token = $newToken; $this->em->persist($this->token); $this->em->flush(); return self::STATUS_NEW_TOKEN; } $newScope = $newToken->getScope(); $newAccessToken = $newToken->getAccessToken(); $existingScope = $oldToken->getScope(); $existingAccessToken = $oldToken->getAccessToken(); // If the channel has the same access token and the same scope, // or no scope has been defined, then we're done. if ($existingScope === $newScope) { return self::STATUS_SAME_SCOPE; } // Is the scope different for the same profile? if ($existingAccessToken !== $newAccessToken) { // If the channel has a different scope and access token, // then create a new token entry for the existing profile. // This takes care of how Google handles scopes for its APIs. $this->token = $newToken; $status = self::STATUS_NEW_TOKEN; } else { // If the channel has the same access token, but a different scope, // then just update the scope for the token. // This takes care of how Facebook deals with scope changes. $this->token = $oldToken; $this->token->setScope($newScope); $status = self::STATUS_NEW_SCOPE; } $this->em->persist($this->token); $this->em->flush(); return $status; }
public function execute($id) { /** @var Campaign $campaign */ $campaign = $this->em->getRepository('CampaignChainCoreBundle:Campaign')->find($id); if (!$campaign) { throw new \Exception('No Campaign found with id: ' . $id); } $now = new \DateTime('now'); // The campaign ended. if ($campaign->getStartDate() < $now && $campaign->getEndDate() < $now) { $campaign->setStatus(Action::STATUS_CLOSED); $this->em->flush(); $this->message = 'The campaign "' . $campaign->getName() . '" ' . 'with ID "' . $campaign->getId() . '" ended, ' . 'thus its status was set to "' . Action::STATUS_CLOSED . '"'; } return self::STATUS_OK; }
public function execute(SymfonyStyle $io = null) { $existingLocations = $this->em->getRepository('CampaignChainCoreBundle:Location')->findAll(); if (empty($existingLocations)) { $io->text('There is no Location to update'); return true; } $supportedLocationModuleIdentifiers = ['campaignchain-twitter-user' => $this->twitterUserMetrics, 'campaignchain-facebook-page' => $this->facebookPageMetrics]; foreach ($existingLocations as $existingLocation) { if (!in_array($existingLocation->getLocationModule()->getIdentifier(), array_keys($supportedLocationModuleIdentifiers))) { continue; } //do we have already a scheduler? $existingScheduler = $this->em->getRepository('CampaignChainCoreBundle:SchedulerReportLocation')->findOneBy(['location' => $existingLocation]); if ($existingScheduler) { continue; } $service = $supportedLocationModuleIdentifiers[$existingLocation->getLocationModule()->getIdentifier()]; $service->schedule($existingLocation); } $this->em->flush(); return true; }
public function execute() { $connection = $this->em->getConnection(); $statement = $connection->prepare('SELECT * FROM campaignchain_campaign_repeating_instance'); $statement->execute(); $instances = $statement->fetchAll(); try { $this->em->getConnection()->beginTransaction(); foreach ($instances as $instance) { /** @var Campaign $campaignParent */ $campaignParent = $this->em->getRepository('CampaignChainCoreBundle:Campaign')->find($instance['repeatingCampaign_id']); /** @var Campaign $campaignChild */ $campaignChild = $this->em->getRepository('CampaignChainCoreBundle:Campaign')->find($instance['scheduledCampaign_id']); $campaignParent->addChild($campaignChild); $campaignChild->setParent($campaignParent); $this->em->flush(); } $this->em->getConnection()->commit(); } catch (\Exception $e) { $this->em->getConnection()->rollback(); throw $e; } }
/** * Search for open jobs and executes them * then show a report about the done job. */ protected function executeJobs() { // Get the Jobs to be processed. $jobsInQueue = $this->em->getRepository('CampaignChainCoreBundle:Job')->getOpenJobsForScheduler($this->scheduler); if (empty($jobsInQueue)) { return; } $this->io->section('Executing jobs now:'); $this->logger->info('Executing {counter} jobs now:', ['counter' => count($jobsInQueue)]); $this->io->progressStart(count($jobsInQueue)); foreach ($jobsInQueue as $jobInQueue) { // Execute job. $this->executeJob($jobInQueue); $this->io->progressAdvance(); } // ensure that the progress bar is at 100% $this->io->progressFinish(); $this->em->clear(); // Get the processed jobs. $jobsProcessed = $this->em->getRepository('CampaignChainCoreBundle:Job')->getProcessedJobsForScheduler($this->scheduler); if (empty($jobsProcessed)) { return; } // Display the results of the execution. $tableHeader = ['Job ID', 'Operation ID', 'Process ID', 'Job Name', 'Job Start Date', 'Job End Date', 'Duration', 'Status', 'Message']; $outputTableRows = []; foreach ($jobsProcessed as $jobProcessed) { $startDate = null; $endDate = null; if ($jobProcessed->getStartDate()) { $startDate = $jobProcessed->getStartDate()->format('Y-m-d H:i:s'); } if ($jobProcessed->getEndDate()) { $endDate = $jobProcessed->getEndDate()->format('Y-m-d H:i:s'); } $jobData = [$jobProcessed->getId(), $jobProcessed->getActionId(), $jobProcessed->getPid(), $jobProcessed->getName(), $startDate, $endDate, $jobProcessed->getDuration() . ' ms', $jobProcessed->getStatus(), $jobProcessed->getMessage()]; $outputTableRows[] = $jobData; if (Job::STATUS_ERROR === $jobProcessed->getStatus()) { $context = array_combine($tableHeader, $jobData); $this->logger->error($jobProcessed->getMessage(), $context); } } $this->io->text('Results of executed actions:'); $this->io->table($tableHeader, $outputTableRows); }
/** * Register activity Channels. */ private function registerChannelRelationships() { if (!count($this->channelRelationships)) { return; } foreach ($this->channelRelationships as $moduleEntity => $channelRelationships) { foreach ($channelRelationships as $bundleIdentifier => $modules) { $bundle = $this->em->getRepository('CampaignChainCoreBundle:Bundle')->findOneByName($bundleIdentifier); foreach ($modules as $moduleIdentifier => $moduleChannels) { $module = $this->em->getRepository('CampaignChainCoreBundle:' . $moduleEntity)->findOneBy(['bundle' => $bundle, 'identifier' => $moduleIdentifier]); foreach ($moduleChannels as $channelURI) { $channelURISplit = explode('/', $channelURI); $channelBundleIdentifier = $channelURISplit[0] . '/' . $channelURISplit[1]; $channelModuleIdentifier = $channelURISplit[2]; /** @var Bundle $channelBundle */ $channelBundle = $this->em->getRepository('CampaignChainCoreBundle:Bundle')->findOneByName($channelBundleIdentifier); /** @var ChannelModule $channelModule */ $channelModule = $this->em->getRepository('CampaignChainCoreBundle:ChannelModule')->findOneBy(['bundle' => $channelBundle, 'identifier' => $channelModuleIdentifier]); if (!$channelModule) { throw new \Exception('The channel URI "' . $channelURI . '" provided in campaignchain.yml of bundle "' . $bundle->getName() . '" for its module "' . $moduleIdentifier . '" does not match an existing channel module.'); } /* * If an updated bundle, then do nothing for an existing * Activity/Channel relationship. * * TODO: Check if existing relationship has been removed * from campaignchain.yml and throw error. */ if ($this->bundleConfigService->isRegisteredBundle($bundle) == self::STATUS_REGISTERED_OLDER) { $method = 'findRegisteredModulesBy' . $moduleEntity; $registeredModules = $this->em->getRepository('CampaignChainCoreBundle:ChannelModule')->{$method}($module); if (count($registeredModules) && $registeredModules[0]->getIdentifier() == $channelModule->getIdentifier()) { continue; } } // Map activity and channel. $module->addChannelModule($channelModule); $this->em->persist($module); } } } } $this->em->flush(); }
/** * @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 string $operationId * @return string * @throws \Exception */ public function execute($operationId) { $this->newsitem = $this->em->getRepository('CampaignChainOperationLinkedInBundle:NewsItem')->findOneByOperation($operationId); if (!$this->newsitem) { throw new \Exception('No Linkedin news item found for an operation with ID: ' . $operationId); } $activity = $this->newsitem->getOperation()->getActivity(); $connection = $this->client->getConnectionByActivity($activity); $this->message = $connection->getCompanyUpdate($activity, $this->newsitem); $likes = 0; if (isset($response['numLikes'])) { $likes = $response['numLikes']; } $comments = 0; if (isset($response['updateComments']) && isset($response['updateComments']['_total'])) { $comments = $response['updateComments']['_total']; } // Add report data. $facts[self::METRIC_LIKES] = $likes; $facts[self::METRIC_COMMENTS] = $comments; $this->factService->addFacts('activity', self::BUNDLE_NAME, $this->newsitem->getOperation(), $facts); return self::STATUS_OK; }
/** * @param array $files * @param bool $doDrop */ public function load(array $files, $doDrop = true) { try { $this->em->getConnection()->beginTransaction(); $userProcessor = new UserProcessor(realpath(SystemUtil::getRootDir() . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR), $this->userService, $this->mimeTypeGuesser, $this->extensionGuesser); // Create Alice manager and fixture set $this->fixtureManager->addProcessor($userProcessor); $set = $this->fixtureManager->createFixtureSet(); // Add the fixture files foreach ($files as $file) { $set->addFile($file, 'yaml'); } $set->setDoDrop($doDrop); $set->setDoPersist(true); $set->setSeed(1337 + 42); // TODO Keep Module data intact $bundles = $this->em->getRepository("CampaignChain\\CoreBundle\\Entity\\Bundle")->findAll(); $modules = $this->em->getRepository("CampaignChain\\CoreBundle\\Entity\\Module")->findAll(); if ($this->fixtureManager->load($set)) { // TODO: Restore modules data foreach ($bundles as $bundle) { $this->em->persist($bundle); } foreach ($modules as $module) { $this->em->persist($module); } $this->em->flush(); $this->em->getConnection()->commit(); return true; } return false; } catch (\Exception $e) { $this->em->getConnection()->rollback(); $this->setException($e); return false; } }
public function execute($operationId) { /** @var Status $status */ $status = $this->em->getRepository('CampaignChainOperationTwitterBundle:Status')->findOneByOperation($operationId); if (!$status) { throw new \Exception('No status message found for an operation with ID: ' . $operationId); } // Check whether the message can be posted in the Location. $isExecutable = $this->validator->isExecutableByLocation($status, $status->getOperation()->getStartDate()); if ($isExecutable['status'] == false) { throw new JobException($isExecutable['message'], ErrorCode::OPERATION_NOT_EXECUTABLE_IN_LOCATION); } /* * If it is a campaign or parent campaign with an interval (e.g. * repeating campaign), we make sure that every URL will be shortened to * avoid a duplicate status message error. */ $options = array(); if ($status->getOperation()->getActivity()->getCampaign()->getInterval() || $status->getOperation()->getActivity()->getCampaign()->getParent() && $status->getOperation()->getActivity()->getCampaign()->getParent()->getInterval()) { $options['shorten_all_unique'] = true; } /* * Process URLs in message and save the new message text, now including * the replaced URLs with the Tracking ID attached for call to action tracking. */ $status->setMessage($this->cta->processCTAs($status->getMessage(), $status->getOperation(), $options)->getContent()); /** @var Client $connection */ $connection = $this->client->connectByActivity($status->getOperation()->getActivity()); $params['status'] = $status->getMessage(); //have images? $images = $this->em->getRepository('CampaignChainHookImageBundle:Image')->getImagesForOperation($status->getOperation()); $mediaIds = []; if ($images) { foreach ($images as $image) { $streamPath = 'gaufrette://images/' . $image->getPath(); $imageRequest = $connection->post('https://upload.twitter.com/1.1/media/upload.json', null, ['media_data' => base64_encode(file_get_contents($streamPath))]); try { $response = $imageRequest->send()->json(); $mediaIds[] = $response['media_id']; } catch (\Exception $e) { } } if ($mediaIds) { $params['media_ids'] = implode(',', $mediaIds); } } /* * @TODO * * If there are URLs in the tweet, they have been shortened. Thus, we'll * pass the expanded URLs as entities in the API call, so that Twitter * can display them when hovering the mouse on a short URL. */ $request = $connection->post('statuses/update.json', null, $params); $response = $request->send()->json(); // TODO // If status code is 403, this means that the same tweet with identical content already exists // This should be checked upon creation of tweet (same with FB!) // Set URL to published status message on Facebook $statusURL = 'https://twitter.com/' . $response['user']['screen_name'] . '/status/' . $response['id_str']; $status->setUrl($statusURL); $status->setIdStr($response['id_str']); // Set Operation to closed. $status->getOperation()->setStatus(Action::STATUS_CLOSED); $location = $status->getOperation()->getLocations()[0]; $location->setIdentifier($response['id_str']); $location->setUrl($statusURL); $location->setName($status->getOperation()->getName()); $location->setStatus(Medium::STATUS_ACTIVE); // Schedule data collection for report $this->report->schedule($status->getOperation()); $this->em->flush(); $this->message = 'The message "' . $response['text'] . '" with the ID "' . $response['id_str'] . '" has been posted on Twitter. See it on Twitter: <a href="' . $statusURL . '">' . $statusURL . '</a>'; return self::STATUS_OK; // } // else { // // Handle errors, if authentication did not work. // // 1) Check if App is installed. // // 2) check if access token is valid and retrieve new access token if necessary. // // Log error, send email, prompt user, ask to check App Key and Secret or to authenticate again // } }
public function getActiveSystem() { return $this->em->getRepository('CampaignChainCoreBundle:System')->findOneBy([], ['id' => 'ASC']); }
/** * @param string $operationId * @return string * @throws \Exception */ public function execute($operationId) { /** @var StatusBase $status */ $status = $this->em->getRepository('CampaignChainOperationFacebookBundle:StatusBase')->findOneByOperation($operationId); if (!$status) { throw new \Exception('No Facebook status found for an operation with ID: ' . $operationId); } // Check whether the message can be posted in the Location. $isExecutable = $this->validator->isExecutableByLocation($status, $status->getOperation()->getStartDate()); if ($isExecutable['status'] == false) { throw new JobException($isExecutable['message'], ErrorCode::OPERATION_NOT_EXECUTABLE_IN_LOCATION); } /* * If it is a campaign or parent campaign with an interval (e.g. * repeating campaign), we make sure that every URL will be shortened to * avoid a duplicate status message error. */ $options = array(); if ($status->getOperation()->getActivity()->getCampaign()->getInterval() || $status->getOperation()->getActivity()->getCampaign()->getParent() && $status->getOperation()->getActivity()->getCampaign()->getParent()->getInterval()) { $options['shorten_all_unique'] = true; } /* * Process URLs in message and save the new message text, now including * the replaced URLs with the Tracking ID attached for call to action * tracking. */ $status->setMessage($this->cta->processCTAs($status->getMessage(), $status->getOperation(), $options)->getContent()); /** @var \Facebook $connection */ $connection = $this->client->connectByActivity($status->getOperation()->getActivity()); if (!$connection) { throw new JobException('Cannot connect to Facebook REST API for Location "' . $status->getOperation()->getActivity()->getLocation()->getUrl() . '"', ErrorCode::CONNECTION_TO_REST_API_FAILED); } $paramsMsg = array(); /* * If an image was attached, we'll first upload the photo to Facebook * and then use the Facebook object ID of the picture in the message. */ $images = $this->em->getRepository('CampaignChainHookImageBundle:Image')->getImagesForOperation($status->getOperation()); if ($images) { $paramsImg = array(); $paramsImg['caption'] = $status->getMessage(); // Avoid that feed shows "... added a new photo" entry automtically. $paramsImg['no_story'] = 1; //Facebook handles only 1 image $paramsImg['url'] = $this->cacheManager->getBrowserPath($images[0]->getPath(), "campaignchain_facebook_photo"); try { $responseImg = $connection->api('/' . $status->getFacebookLocation()->getIdentifier() . '/photos', 'POST', $paramsImg); $paramsMsg['object_attachment'] = $responseImg['id']; } catch (\Exception $e) { throw new ExternalApiException($e->getMessage() . '. Parameters of REST API call: ' . json_encode($paramsImg), $e->getCode(), $e); } } if ($status instanceof UserStatus) { $privacy = array('value' => $status->getPrivacy()); $paramsMsg['privacy'] = json_encode($privacy); } $paramsMsg['message'] = $status->getMessage(); try { $responseMsg = $connection->api('/' . $status->getFacebookLocation()->getIdentifier() . '/feed', 'POST', $paramsMsg); } catch (\Exception $e) { throw new ExternalApiException($e->getMessage() . '. Parameters of REST API call: ' . json_encode($paramsMsg), $e->getCode(), $e); } $connection->destroySession(); // Set URL to published status message on Facebook $statusURL = 'https://www.facebook.com/' . str_replace('_', '/posts/', $responseMsg['id']); $status->setUrl($statusURL); $status->setPostId($responseMsg['id']); // Set Operation to closed. $status->getOperation()->setStatus(Action::STATUS_CLOSED); $location = $status->getOperation()->getLocations()[0]; $location->setIdentifier($responseMsg['id']); $location->setUrl($statusURL); $location->setName($status->getOperation()->getName()); $location->setStatus(Medium::STATUS_ACTIVE); // Schedule data collection for report $this->report->schedule($status->getOperation()); $this->em->flush(); $this->message = 'The message "' . $paramsMsg['message'] . '" with the ID "' . $responseMsg['id'] . '" has been posted on Facebook'; if ($status instanceof UserStatus) { $this->message .= ' with privacy setting "' . $privacy['value'] . '"'; } $this->message .= '. See it on Facebook: <a href="' . $statusURL . '">' . $statusURL . '</a>'; return self::STATUS_OK; }