Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

twitter provider error #44

Open
lukeman83 opened this issue Feb 3, 2013 · 18 comments
Open

twitter provider error #44

lukeman83 opened this issue Feb 3, 2013 · 18 comments

Comments

@lukeman83
Copy link

Hi,
I integrated FOSUserBundle, FOSFacebookBundle, FOSMessageBundle and it was ok!
Now I'm integrating FOSTwitterBundle together without twitter anywhere and I have this problem:

ErrorException: Catchable Fatal Error: Argument 2 passed to project\UserBundle\Security\User\Provider\TwitterProvider::__construct() must be an instance of FOS\UserBundle\Entity\UserManager, instance of FOS\UserBundle\Doctrine\UserManager given, called in /Applications/MAMP/htdocs/project/app/cache/dev/appDevDebugProjectContainer.php on line 2085 and defined in /Applications/MAMP/htdocs/project/src/project/UserBundle/Security/User/Provider/TwitterProvider.php line 25

What's the solution?

Another question...
I read FOStwitterBundle documentation and it says:

//app/security.yml public: pattern: /.* anonymous: true fos_twitter: true logout: true and //app/security.yml public: pattern: / fos_twitter: login_path: /twitter/login check_path: /twitter/login_check default_target_path: / provider: my_fos_twitter_provider anonymous: ~

Which is the right way?

Many thanks!!

@stof
Copy link
Member

stof commented Feb 12, 2013

you should typehint the UserManagerInterface, not an implementation

@lukeman83
Copy link
Author

I'm using documentation code.
Is this not ok?

<?php
// src/project/YourBundle/Security/User/Provider/TwitterUserProvider.php


namespace project\YourBundle\Security\User\Provider;

use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\HttpFoundation\Session;
use \TwitterOAuth;
use FOS\UserBundle\Entity\UserManager;
use Symfony\Component\Validator\Validator;

class TwitterUserProvider implements UserProviderInterface
{
    /** 
     * @var \Twitter
     */
    protected $twitter_oauth;
    protected $userManager;
    protected $validator;
    protected $session;

    public function __construct(TwitterOAuth $twitter_oauth, UserManager $userManager,Validator $validator, Session $session)
    {   
        $this->twitter_oauth = $twitter_oauth;
        $this->userManager = $userManager;
        $this->validator = $validator;
        $this->session = $session;
    }   

    public function supportsClass($class)
    {   
        return $this->userManager->supportsClass($class);
    }   

    public function findUserByTwitterId($twitterID)
    {   
        return $this->userManager->findUserBy(array('twitterID' => $twitterID));
    }   

    public function loadUserByUsername($username)
    {
        $user = $this->findUserByTwitterId($username);

        $this->twitter_oauth->setOAuthToken($this->session->get('access_token'), $this->session->get('access_token_secret'));

        try {
            $info = $this->twitter_oauth->get('account/verify_credentials');
        } catch (Exception $e) {
            $info = null;
        }

        if (!empty($info)) {
            if (empty($user)) {
                $user = $this->userManager->createUser();
                $user->setEnabled(true);
                $user->setPassword('');
                $user->setAlgorithm('');
            }

            $username = $info->screen_name;

            $user->setTwitterID($info->id);
            $user->setTwitterUsername($username);
            $user->setEmail('');
            $user->setFirstname($info->name);

            $this->userManager->updateUser($user);
        }

        if (empty($user)) {
            throw new UsernameNotFoundException('The user is not authenticated on twitter');
        }

        return $user;
    }

    public function refreshUser(UserInterface $user)
    {
        if (!$this->supportsClass(get_class($user)) || !$user->getTwitterID()) {
            throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
        }

        return $this->loadUserByUsername($user->getTwitterID());
    }
}

@stof
Copy link
Member

stof commented Feb 12, 2013

@lukeman83 typehint the UserManagerInterface in your constructor instead of the implementation (which is not the one used by your FOSUserBundle setup)

@lukeman83
Copy link
Author

Like this?

public function __construct(TwitterOAuth $twitter_oauth, Validator $validator, Session $session) { $this->twitter_oauth = $twitter_oauth; $this->userManager = new UserManager(); $this->validator = $validator; $this->session = $session; }

@stof
Copy link
Member

stof commented Feb 12, 2013

I'm talking about changing the typehint, not about creating a new manager magically (which don't work anyway as it has some required dependencies):

 use \TwitterOAuth;
-use FOS\UserBundle\Entity\UserManager;
+use FOS\UserBundle\Model\UserManagerInterface;
 use Symfony\Component\Validator\Validator;

 class TwitterUserProvider implements UserProviderInterface
 {
     /** 
      * @var \Twitter
      */
     protected $twitter_oauth;
     protected $userManager;
     protected $validator;
     protected $session;

-    public function __construct(TwitterOAuth $twitter_oauth, UserManager $userManager,Validator $validator, Session $session)
+    public function __construct(TwitterOAuth $twitter_oauth, UserManagerInterface $userManager,Validator $validator, Session $session)
     {   

On a side node, you should also use the ValidatorInterface for the typehint instead of the implementation.

@lukeman83
Copy link
Author

I did same things for Validator and Session.
At the moment my TwitterProvider.php is this:

namespace project\UserBundle\Security\User\Provider;

use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use \TwitterOAuth;
use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Component\Validator\ValidatorInterface;

class TwitterProvider implements UserProviderInterface
{
    /** 
     * @var \Twitter
     */
    protected $twitter_oauth;
    protected $userManager;
    protected $validator;
    protected $session;

    public function __construct(TwitterOAuth $twitter_oauth,  UserManagerInterface $userManager,  ValidatorInterface $validator, SessionInterface $session)
    {   
        $this->twitter_oauth = $twitter_oauth;
        $this->userManager = $userManager;
        $this->validator = $validator;
        $this->session = $session;
    }   

    public function supportsClass($class)
    {   
        return $this->userManager->supportsClass($class);
    }   

    public function findUserByTwitterId($twitterID)
    {   
        return $this->userManager->findUserBy(array('twitterID' => $twitterID));
    }   

    public function loadUserByUsername($username)
    {
        $user = $this->findUserByTwitterId($username);


         $this->twitter_oauth->setOAuthToken( $this->session->get('access_token') , $this->session->get('access_token_secret'));

        try {
             $info = $this->twitter_oauth->get('account/verify_credentials');
        } catch (Exception $e) {
             $info = null;
        }

        if (!empty($info)) {
            if (empty($user)) {
                $user = $this->userManager->createUser();
                $user->setEnabled(true);
                $user->setPassword('');
                $user->setAlgorithm('');
            }

            $username = $info->screen_name;


            $user->setTwitterID($info->id);
            $user->setTwitterUsername($username);
            $user->setEmail('');
            $user->setFirstname($info->name);

            $this->userManager->updateUser($user);
        }

        if (empty($user)) {
            throw new UsernameNotFoundException('The user is not authenticated on twitter');
        }

        return $user;

    }

    public function refreshUser(UserInterface $user)
    {
        if (!$this->supportsClass(get_class($user)) || !$user->getTwitterID()) {
            throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
        }

        return $this->loadUserByUsername($user->getTwitterID());
    }
}

This is the error I get:

User provider "FOS\TwitterBundle\Security\Authentication\Provider\TwitterProvider" must implement "Symfony\Component\Security\Core\User\UserProviderInterface".

@stof
Copy link
Member

stof commented Feb 17, 2013

what is your security config ? FOS\TwitterBundle\Security\Authentication\Provider\TwitterProvider is not a userr provider. It is an authentication provider

@lukeman83
Copy link
Author

imports:    
    - { resource: facebookParameters.ini }

jms_security_extra:
    secure_all_services: false
    expressions: true

security:
    #factories:
    #    - "%kernel.root_dir%/../vendor/bundles/FOS/FacebookBundle/Resources/config/security_factories.xml"
    providers:
        my_fos_facebook_provider:
            id: my.facebook.user 
        my_fos_twitter_provider:
            id: my.twitter.user 
        fos_userbundle:
            id: fos_user.user_manager
        fos_twitter:
            id: fos_twitter.auth
    encoders:
        FOS\UserBundle\Model\UserInterface: sha512
        Symfony\Component\Security\Core\User\User: plaintext
    firewalls:
        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                csrf_provider: form.csrf_provider
            fos_facebook:
                app_url: %facebookAppUrl%
                server_url: %facebookServerUrl%
                login_path: /login
                check_path: /login_fb_check
                default_target_path: /
                provider: my_fos_facebook_provider
            logout:
                handlers: ["fos_facebook.logout_handler"]
            anonymous:    true
        secured:
                pattern:   /secured/.*
                fos_twitter: true

        dev:
                pattern:  ^/(_(profiler|wdt)|css|images|js)/
                security: false
        public:
                pattern: /.*
                anonymous: true
                fos_twitter: true
                logout: true

    access_control:
        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: /.*, role: [IS_AUTHENTICATED_ANONYMOUSLY] }
        - { path: ^/admin/, role: ROLE_ADMIN }
    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

@stof
Copy link
Member

stof commented Feb 17, 2013

The indentation of your YAML snippet is missing, making it wrong.

@stof
Copy link
Member

stof commented Feb 17, 2013

And this is not the full security config

@lukeman83
Copy link
Author

I updated it.

@stof
Copy link
Member

stof commented Feb 17, 2013

fos_twitter.auth is not a user provider. You should not configure a user provider using this id.

@lukeman83
Copy link
Author

I'm sorry!
I didn't understand what is the correct way to solve this problem.
Which Id must I use for user provider?
Thanks a lot!

@lukeman83
Copy link
Author

Can you help me please!

@gregquat
Copy link

@stof "fos_twitter.auth is not a user provider. You should not configure a user provider using this id."
=> so there is a mistake in the documentation (https://github.com/FriendsOfSymfony/FOSTwitterBundle#installation, see point 4)

@stof
Copy link
Member

stof commented Mar 21, 2013

hmm, indeed

@pohlaniacz
Copy link

I have the same problem, so what is the right version of installing FOSTwitterBundle?

@gregquat
Copy link

gregquat commented May 5, 2013

Here is the version I use 👍

security:
  #...
    providers:
      #...
      acme_twitter_provider:
        id: acme.twitter.user # a custom provider

firewalls:
  main:
    #...
    fos_twitter:
      login_path: /twitter/login
      check_path: twitter_login_check
      default_target_path: /welcome-twitter # a custom route
      provider: acme_twitter_provider # my custom provider (see above)

Hope it will help

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants