{"action":"created","issue":{"url":"https://api.github.com/repos/symfony/symfony/issues/29257","repository_url":"https://api.github.com/repos/symfony/symfony","labels_url":"https://api.github.com/repos/symfony/symfony/issues/29257/labels{/name}","comments_url":"https://api.github.com/repos/symfony/symfony/issues/29257/comments","events_url":"https://api.github.com/repos/symfony/symfony/issues/29257/events","html_url":"https://github.com/symfony/symfony/issues/29257","id":382008665,"node_id":"MDU6SXNzdWUzODIwMDg2NjU=","number":29257,"title":"[DoctrineBridge] Custom EntityRepository as service breaks EntityUserProvider","user":{"login":"lrlopez","id":547387,"node_id":"MDQ6VXNlcjU0NzM4Nw==","avatar_url":"https://avatars2.githubusercontent.com/u/547387?v=4","gravatar_id":"","url":"https://api.github.com/users/lrlopez","html_url":"https://github.com/lrlopez","followers_url":"https://api.github.com/users/lrlopez/followers","following_url":"https://api.github.com/users/lrlopez/following{/other_user}","gists_url":"https://api.github.com/users/lrlopez/gists{/gist_id}","starred_url":"https://api.github.com/users/lrlopez/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lrlopez/subscriptions","organizations_url":"https://api.github.com/users/lrlopez/orgs","repos_url":"https://api.github.com/users/lrlopez/repos","events_url":"https://api.github.com/users/lrlopez/events{/privacy}","received_events_url":"https://api.github.com/users/lrlopez/received_events","type":"User","site_admin":false},"labels":[{"id":100079,"node_id":"MDU6TGFiZWwxMDAwNzk=","url":"https://api.github.com/repos/symfony/symfony/labels/Bug","name":"Bug","color":"e10c02","default":false},{"id":337187703,"node_id":"MDU6TGFiZWwzMzcxODc3MDM=","url":"https://api.github.com/repos/symfony/symfony/labels/DoctrineBridge","name":"DoctrineBridge","color":"dddddd","default":false},{"id":237003792,"node_id":"MDU6TGFiZWwyMzcwMDM3OTI=","url":"https://api.github.com/repos/symfony/symfony/labels/Status:%20Needs%20Review","name":"Status: Needs Review","color":"ededed","default":false},{"id":520300257,"node_id":"MDU6TGFiZWw1MjAzMDAyNTc=","url":"https://api.github.com/repos/symfony/symfony/labels/Status:%20Waiting%20feedback","name":"Status: Waiting feedback","color":"fef2c0","default":false},{"id":2932845,"node_id":"MDU6TGFiZWwyOTMyODQ1","url":"https://api.github.com/repos/symfony/symfony/labels/Unconfirmed","name":"Unconfirmed","color":"444444","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":4,"created_at":"2018-11-18T22:40:48Z","updated_at":"2018-11-19T14:17:21Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"**Description**  \r\n\r\nAfter reading [this post by Thomas Votruba](https://www.tomasvotruba.cz/blog/2017/10/16/how-to-use-repository-with-doctrine-as-service-in-symfony/) about migrating Doctrine entity repositories into services in order to use them with DI, I started to apply it into a Symfony 3.4 project I'm working on.\r\n\r\nEverything looked ok (it should really be considered as a best practice because the code is much cleaner) until I stumbled in a roadblock with the guard authentication. It seems that `EntityUserProvider` uses the Doctrine locator in order to find `EntityRepository` related to the User entity, but the `repositoryClass` parameter must be removed in order to avoid circular references. This implies that Doctrine locator doesn't work anymore (it just returns a generic `EntityRepository`) and `EntityUserProvider` fails because the generic class doesn't implement the `UserLoaderInterface` interface (even though the custom repository does).\r\n\r\nSo, I suggest adding a new config option to the `entity` user provider in `security.yml` called `repository` that can be stated to point to the right repository class. \r\n\r\nSo I propose to change:\r\n```php\r\n    // src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php\r\n    /**\r\n     * {@inheritdoc}\r\n     */\r\n    public function loadUserByUsername($username)\r\n    {\r\n        $repository = $this->getRepository();\r\n        if (null !== $this->property) {\r\n            $user = $repository->findOneBy(array($this->property => $username));\r\n        } else {\r\n            if (!$repository instanceof UserLoaderInterface) {\r\n                throw new \\InvalidArgumentException(sprintf('You must either make the \"%s\" entity Doctrine Repository (\"%s\") implement \"Symfony\\Bridge\\Doctrine\\Security\\User\\UserLoaderInterface\" or set the \"property\" option in the corresponding entity provider configuration.', $this->classOrAlias, \\get_class($repository)));\r\n            }\r\n\r\n            $user = $repository->loadUserByUsername($username);\r\n        }\r\n\r\n        if (null === $user) {\r\n            throw new UsernameNotFoundException(sprintf('User \"%s\" not found.', $username));\r\n        }\r\n\r\n        return $user;\r\n    }\r\n```\r\nto something similar to: \r\n```php\r\n/**\r\n     * {@inheritdoc}\r\n     */\r\n    public function loadUserByUsername($username)\r\n    {\r\n        if (null !== $this->repository) {\r\n            $repository = $this->repository;\r\n        } else {\r\n            $repository = $this->getRepository();\r\n        }\r\n        if (null !== $this->property) {\r\n            $user = $repository->findOneBy(array($this->property => $username));\r\n        } else {\r\n            if (!$repository instanceof UserLoaderInterface) {\r\n                throw new \\InvalidArgumentException(sprintf('You must either make the \"%s\" entity Doctrine Repository (\"%s\") implement \"Symfony\\Bridge\\Doctrine\\Security\\User\\UserLoaderInterface\", set \"repository\" to a custom repository that implements that interface, or set the \"property\" option,  in the corresponding entity provider configuration.', $this->classOrAlias, \\get_class($repository)));\r\n            }\r\n\r\n            $user = $repository->loadUserByUsername($username);\r\n        }\r\n\r\n        if (null === $user) {\r\n            throw new UsernameNotFoundException(sprintf('User \"%s\" not found.', $username));\r\n        }\r\n\r\n        return $user;\r\n    }\r\n```\r\nAnd then allow the entity provider configuration to host the new \"repository\" option.\r\n\r\nWhat do you think?\r\n\r\n**Example**  \r\n```yaml\r\n    # config/packages/security.yaml\r\n    # ...\r\n\r\n    providers:\r\n        our_db_provider:\r\n            entity:\r\n                class: App\\Entity\\User\r\n                repository: App\\Repository\\UserRepository\r\n    # ...\r\n```\r\n\r\nShould it be backported to Symfony 3.4 I would make the PR myself in order to fix this annoying problem.\r\n\r\nNOTE: I've submitted this as a bug report because it breaks a expected behavior with custom entity providers as services.\r\n"},"comment":{"url":"https://api.github.com/repos/symfony/symfony/issues/comments/439907145","html_url":"https://github.com/symfony/symfony/issues/29257#issuecomment-439907145","issue_url":"https://api.github.com/repos/symfony/symfony/issues/29257","id":439907145,"node_id":"MDEyOklzc3VlQ29tbWVudDQzOTkwNzE0NQ==","user":{"login":"chalasr","id":7502063,"node_id":"MDQ6VXNlcjc1MDIwNjM=","avatar_url":"https://avatars0.githubusercontent.com/u/7502063?v=4","gravatar_id":"","url":"https://api.github.com/users/chalasr","html_url":"https://github.com/chalasr","followers_url":"https://api.github.com/users/chalasr/followers","following_url":"https://api.github.com/users/chalasr/following{/other_user}","gists_url":"https://api.github.com/users/chalasr/gists{/gist_id}","starred_url":"https://api.github.com/users/chalasr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chalasr/subscriptions","organizations_url":"https://api.github.com/users/chalasr/orgs","repos_url":"https://api.github.com/users/chalasr/repos","events_url":"https://api.github.com/users/chalasr/events{/privacy}","received_events_url":"https://api.github.com/users/chalasr/received_events","type":"User","site_admin":false},"created_at":"2018-11-19T14:17:21Z","updated_at":"2018-11-19T14:17:21Z","author_association":"MEMBER","body":"I confirm that making the repository extend `ServiceEntityRepository` + setting `repositoryClass` on the entity works fine and does not cause any circular reference on my side.  You should indeed use it instead.\r\nI'm not convinced EntityUserProvider should support any other way to register doctrine repositories as services neither."}}
{"actor":{"display_login":"chalasr"}}