/**
  * Register social login services
  *
  * @param  Application $app Silex application
  */
 public function register(Application $app)
 {
     $app['social-login.controller'] = $app->share(function ($app) {
         $config = $app['config']->load('social-login');
         $controller = new SocialLoginController();
         $controller->setSocialLoginService($app['social-login.service'])->setConfig($config)->setServiceFactory(new ServiceFactory())->setSession($app['session']);
         return $controller;
     });
     $app['social-login.mapper'] = $app->share(function ($app) {
         return new SocialLoginMapper($app['db'], new SocialLoginEntity());
     });
     $app['social-login.service'] = $app->share(function ($app) {
         $service = new SocialLoginService();
         $service->setUserService($app['user.service'])->setSocialLoginMapper($app['social-login.mapper'])->setOAuthStorage($app['oauth.storage']);
         return $service;
     });
     $app->get('/social-login/{provider}', 'social-login.controller:login')->bind('social-login-auth');
     $app->get('/social-login/{provider}/link', 'social-login.controller:link')->bind('social-link-auth');
     $app->get('/social-login/{provider}/callback', 'social-login.controller:callback')->bind('social-login-callback');
     $this->setFirewalls($app);
 }
 /**
  * Callback for OAuth authentication requests
  *
  * @param  Request  $request
  * @return Response
  */
 public function callback(Request $request)
 {
     // Check to see if this provider exists and has a callback implemented
     $provider = strtolower($request->attributes->get('provider'));
     if (!$this->providerExists($provider)) {
         return $this->createNotFoundResponse();
     }
     if (!method_exists($this, $provider)) {
         throw new LogicException(sprintf('Callback for provider \'%s\' not implemented', $provider));
     }
     // Use provider service and access token from provider to create a LoginRequest for our app
     $code = $request->query->get('code');
     $providerService = $this->getServiceByProvider($provider);
     $providerToken = $providerService->requestAccessToken($code);
     $socialLoginRequest = $this->{$provider}($providerService, $providerToken);
     // Handle login or link-account request and redirect to the redirect-url
     $state = (int) $request->query->get('state');
     try {
         if ($state === self::ACTION_LOGIN_WITH_ACCOUNT) {
             $token = $this->service->handleLoginRequest($socialLoginRequest);
         } elseif ($state === self::ACTION_LINK_ACCOUNT) {
             $token = $this->service->handleLinkRequest($socialLoginRequest, $this->session->get('user'));
         } else {
             return new Response('State parameter not set', 422);
         }
         $redirect = $this->config['redirect-url'];
         $redirect .= '?' . http_build_query($token);
     } catch (NoLinkedAccountException $e) {
         $redirect = $this->config['redirect-url'];
         $redirect .= '?login_failure=1&error=no_linked_account';
     } catch (LinkedAccountExistsException $e) {
         $redirect = $this->config['redirect-url'];
         $redirect .= '?login_failure=1&error=account_already_linked';
     } catch (OutOfBoundsException $e) {
         $redirect = $this->config['redirect-url'];
         $redirect .= '?login_failure=1';
         if ($e->getCode() === SocialLoginService::EXCEPTION_ACCOUNT_NOT_FOUND) {
             $redirect .= '&error=account_not_found';
         }
     }
     $response = new Response();
     $response->setStatusCode(301);
     $response->headers->set('Location', $redirect);
     return $response;
 }