/**
  * @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;
 }
 /**
  * @param $resourceOwner
  * @param $applicationInfo
  * @param bool $sameToken
  *
  * @throws \Exception
  */
 public function authenticate($resourceOwner, $applicationInfo, $sameToken = false)
 {
     // Get application credentials
     $oauthApp = $this->container->get('campaignchain.security.authentication.client.oauth.application');
     $application = $oauthApp->getApplication($resourceOwner);
     $bundleParams = $this->container->getParameter('campaignchain_security_authentication_client_oauth');
     if (isset($_SERVER['HTTPS']) && (!empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'off')) {
         $hostScheme = 'https://';
     } else {
         $hostScheme = 'http://';
     }
     $config = array("base_url" => $hostScheme . $_SERVER['HTTP_HOST'] . $this->container->get('router')->generate('campaignchain_security_authentication_client_oauth_login'), "providers" => array($resourceOwner => array("enabled" => true, "keys" => array($applicationInfo['key_labels'][0] => $application->getKey(), $applicationInfo['secret_labels'][0] => $application->getSecret()))), "debug_mode" => $bundleParams['debug_mode'], "debug_file" => $bundleParams['debug_file']);
     $config['providers'][$resourceOwner] = array_merge($config['providers'][$resourceOwner], $applicationInfo['parameters']);
     if (isset($applicationInfo['wrapper'])) {
         $config['providers'][$resourceOwner]['wrapper']['class'] = $applicationInfo['wrapper']['class'];
         $config['providers'][$resourceOwner]['wrapper']['path'] = $this->container->get('kernel')->getRootDir() . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $applicationInfo['wrapper']['path']);
     }
     try {
         $hybridauth = new Hybrid_Auth($config);
         $resource = $hybridauth->authenticate($resourceOwner);
         $this->profile = $resource->getUserProfile();
         $accessToken = $resource->getAccessToken();
         $hybridauth->logoutAllProviders();
         $token = new Token();
         $token->setApplication($application);
         $token->setAccessToken($accessToken["access_token"]);
         $token->setTokenSecret($accessToken["access_token_secret"]);
         $token->setRefreshToken($accessToken["refresh_token"]);
         $token->setExpiresIn($accessToken["expires_in"]);
         $token->setExpiresAt($accessToken["expires_at"]);
         if (isset($resource->adapter->api->api_base_url)) {
             $token->setEndpoint($resource->adapter->api->api_base_url);
         }
         if (isset($applicationInfo['parameters']['scope'])) {
             $token->setScope($applicationInfo['parameters']['scope']);
         }
         $this->oauthToken = $this->container->get('campaignchain.security.authentication.client.oauth.token');
         return $this->oauthToken->setToken($token, $sameToken);
     } catch (\Exception $e) {
         throw new ExternalApiException($e->getMessage(), $e->getCode(), $e);
     }
 }