Symfony2 access user and doctrine in a service

回眸只為那壹抹淺笑 提交于 2019-12-09 16:11:33

问题


I'm running the equivalent of this code in lots and lots of controller actions, basically it grabs the user's username, and if that username is attached to a blog entity it will allow the user to see the blog entity(s):

    $em = $this->getDoctrine()->getManager();
    $user = $this->get('security.context')->getToken()->getUser();
    $entities = $em->getRepository('MySiteBundle:Blog')->findBy(array('user' => $user));

    return $this->render('MySiteBundle:Blog:index.html.twig', array(
        'entities' => $entities,

I want to move it into a service so I can cut down on code repetition. I want to avoid doing as much logic in my controllers as possible.

That being said, I'm not sure how I can access the user session and doctrine in a service.

Here's my services.yml:

mysite.user.blog:
    class: MySite\SiteBundle\Services\BlogUser

And here's how I was attempting to call it in the controller:

public function testAction() {
    $response = $this->get('mysite.user.blog');
    return new Response($response);
}

I did try using an event subscriber/listener tag, but that doesn't seem to accomplish the task I want.

Here is my completely horrible attempt at a service. I couldn't get any response from it without using a constructor.

namespace MySite\SiteBundle\Services;

use MySite\SiteBundle\Entity\Blog;

class BlogUser {

    protected $entities;

    public function __construct(){
        $em = $this->getDoctrine()->getManager();
        $user = $this->get('security.context')->getToken()->getUser();
        $this->entities = $em->getRepository('MySiteBundle:Blog')->findBy(array('user' => $user));
    }
}

Am I going about this the completely wrong way? Is there a better way that I'm missing?

EDIT/ANSWER:

modified my naming convention a little:

//services.yml
mysite.user.blog.entities:
    class: Mysite\SiteBundle\Services\BlogUser
    arguments: ["@doctrine.orm.entity_manager", "@security.context"]

In the controller action:

$userEntities = $this->get('mysite.user.blog.entities');
$entities = $userEntities->getEntities();

In the service itself:

class BlogUser {

    protected $entities;

    public function __construct($em, $securityContext){
        $user = $securityContext->getToken()->getUser();
        $this->entities = $em->getRepository('MySiteBundle:Blog')->findBy(array('user' => $user));
    }
    public function getEntities(){
        return $this->entities;
    }
}

Still needs two lines to get the $entities variable in the controller, but this is way better than defining the same thing over and over.


回答1:


"Security.context" has been deprecated since Symfony 2.6

After some community discussions, it was decided that SecurityContext gives too many dependencies to retrieve a simple Token/User object. That's why, starting with Symfony 2.6, thesecurity.context service has been deprecated and split into two new services:security.authorization_checker and security.token_storage.

Source

Thus, the new way to do it would be, first configure your service as:

mysite.user.blog:
    class: MySite\SiteBundle\Services\BlogUser
    arguments: ["@doctrine.orm.entity_manager", "@security.token_storage"]

Then in the service class constructor:

class BlogUser
{
    protected $user;
    protected $entities;

    public function __construct(EntityManager $em, TokenStorage $tokenStorage)
    {
        $this->user = $tokenStorage->getToken()->getUser();
        $this->entities = $em->getRepository('MySiteBundle:Blog')->findBy(array('user' => $user));
    }
}



回答2:


Yes, you are doing it in wrong way. Let's look at your code:

    # call to undefined object method getDoctrine()
    $em = $this->getDoctrine()->getManager();
    # call to undefined object method get()
    $user = $this->get('security.context')->getToken()->getUser();

You cannot call getting entitymanager and security.context in your service in the same way like in your controller. Instead, you have to inject entitymanager and security.context services. Example:

# services.yml
mysite.user.blog:
    class: MySite\SiteBundle\Services\BlogUser
    calls:
        - [ setUserFromSecurityContext, [ @security.context ]]
        - [ setEntityManager, [ @doctrine.orm.entity_manager ]]

And improved service:

namespace Catablog\SiteBundle\Services;

use MySite\SiteBundle\Entity\Blog;

class BlogUser {
    private $entityManager;
    private $user;

    public function setEntityManager(EntityManager $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function setUserFromSecurityContext(SecurityContext $securityContext)
    {
        # notice, there are a cases when `getToken()` returns null, so improve this
        $this->user = $securityContext->getToken()->getUser();
    }
    public function getEntities(){
        # your code here
    }
}

More info about Dependency injection




回答3:


You are looking on how to 'inject' other services into your custom service. Take a look at Service Container documentation.

In your case, you can inject doctrine.orm.entity_manager and security.context services into your BlogUser class via constructor injection. For example:

class BlogUser {

    public function __construct($em, $securityContext) {
        $user = $securityContext->getToken()->getUser();
        $this->entities = $em->getRepository('MySiteBundle:Blog')->findBy(array('user' => $user));
    }

}

And configure your service as the following:

mysite.user.blog:
    class: MySite\SiteBundle\Services\BlogUser
    arguments:    ["@doctrine.orm.entity_manager", "@security.context"]


来源:https://stackoverflow.com/questions/18223988/symfony2-access-user-and-doctrine-in-a-service

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!