FriendsOfSymfony / FOSTwitterBundle

UNMAINTAINED. Please use HWIOAuthBundle as a replacement for FOSTwitterBundle.
http://friendsofsymfony.github.com/
146 stars 38 forks source link

twitter provider error #44

Open lukeman83 opened 11 years ago

lukeman83 commented 11 years ago

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 commented 11 years ago

you should typehint the UserManagerInterface, not an implementation

lukeman83 commented 11 years ago

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 commented 11 years ago

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

lukeman83 commented 11 years ago

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 commented 11 years ago

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 commented 11 years ago

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 commented 11 years ago

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

lukeman83 commented 11 years ago
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 commented 11 years ago

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

stof commented 11 years ago

And this is not the full security config

lukeman83 commented 11 years ago

I updated it.

stof commented 11 years ago

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

lukeman83 commented 11 years ago

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 commented 11 years ago

Can you help me please!

gregquat commented 11 years ago

@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 commented 11 years ago

hmm, indeed

pohlaniacz commented 11 years ago

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

gregquat commented 11 years ago

Here is the version I use :+1:

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